Merge branch 'develop' into auto-linewrap

This commit is contained in:
Jonathan van der Steege 2022-07-17 14:27:31 +02:00
commit 488890d165
53 changed files with 539 additions and 448 deletions

View file

@ -39,12 +39,7 @@ runs:
echo 'DEPS_INSTALLED=true' >> $GITHUB_ENV echo 'DEPS_INSTALLED=true' >> $GITHUB_ENV
shell: bash shell: bash
- name: Linting - name: Linting & Testing
if: ${{ env.DEPS_INSTALLED == 'true' }} if: ${{ env.DEPS_INSTALLED == 'true' }}
run: poetry run poe ci-lint run: poetry run poe test
shell: bash
- name: Testing
if: ${{ env.DEPS_INSTALLED == 'true' }}
run: poetry run poe ci-test
shell: bash shell: bash

View file

@ -2,28 +2,18 @@
## [Unreleased](https://github.com/jrnl-org/jrnl/) ## [Unreleased](https://github.com/jrnl-org/jrnl/)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.0-beta...HEAD) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.0...HEAD)
**Fixed bugs:** **Implemented enhancements:**
- Adding new entry with date only works with format m.d.Y [\#1509](https://github.com/jrnl-org/jrnl/issues/1509) - Warn user when there are duplicate keys in the config file [\#1415](https://github.com/jrnl-org/jrnl/issues/1415)
**Build:** ## [v3.0](https://pypi.org/project/jrnl/v3.0/) (2022-07-09)
- Use tox [\#1361](https://github.com/jrnl-org/jrnl/issues/1361) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.0-beta2...v3.0)
- Stop hardcoding bot info in changelog pipeline [\#1506](https://github.com/jrnl-org/jrnl/pull/1506) ([wren](https://github.com/wren))
- Fix Poetry caching for accessibility tests [\#1505](https://github.com/jrnl-org/jrnl/pull/1505) ([wren](https://github.com/wren))
- Implement Tox for testing [\#1504](https://github.com/jrnl-org/jrnl/pull/1504) ([wren](https://github.com/wren))
- Replace `make` with python alternative \(`poe`\) [\#1503](https://github.com/jrnl-org/jrnl/pull/1503) ([wren](https://github.com/wren))
- Update copyright year [\#1502](https://github.com/jrnl-org/jrnl/pull/1502) ([wren](https://github.com/wren))
## [v3.0-beta](https://pypi.org/project/jrnl/v3.0-beta/) (2022-06-11)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.8.4...v3.0-beta)
**Implemented enhancements:** **Implemented enhancements:**
- Add --change-time command to change the timestamp of an entry [\#1429](https://github.com/jrnl-org/jrnl/issues/1429)
- Show name of journal when creating a password/encrypting [\#1478](https://github.com/jrnl-org/jrnl/pull/1478) ([jonakeys](https://github.com/jonakeys)) - Show name of journal when creating a password/encrypting [\#1478](https://github.com/jrnl-org/jrnl/pull/1478) ([jonakeys](https://github.com/jonakeys))
- Rework how all output and messaging works in jrnl [\#1475](https://github.com/jrnl-org/jrnl/pull/1475) ([wren](https://github.com/wren)) - Rework how all output and messaging works in jrnl [\#1475](https://github.com/jrnl-org/jrnl/pull/1475) ([wren](https://github.com/wren))
- Implement --change-time flag [\#1452](https://github.com/jrnl-org/jrnl/pull/1452) ([richardjs](https://github.com/richardjs)) - Implement --change-time flag [\#1452](https://github.com/jrnl-org/jrnl/pull/1452) ([richardjs](https://github.com/richardjs))
@ -32,14 +22,7 @@
**Fixed bugs:** **Fixed bugs:**
- --debug leads to logging error after composing new entry [\#1496](https://github.com/jrnl-org/jrnl/issues/1496) - Display message when no edits take place [\#1510](https://github.com/jrnl-org/jrnl/pull/1510) ([apainintheneck](https://github.com/apainintheneck))
- Using -not argument by itself leads to new entry creation [\#1472](https://github.com/jrnl-org/jrnl/issues/1472)
- Empty config file leads to confusing error message [\#1420](https://github.com/jrnl-org/jrnl/issues/1420)
- "Entry not saved" text doesn't appear in default stdin editor [\#1419](https://github.com/jrnl-org/jrnl/issues/1419)
- jrnl --encrypt doesn't prompt me for password change [\#1358](https://github.com/jrnl-org/jrnl/issues/1358)
- '-not -contains x' raises an AttributeError exception [\#1350](https://github.com/jrnl-org/jrnl/issues/1350)
- Exception when providing folder name of folder that does not exist as journal path [\#1293](https://github.com/jrnl-org/jrnl/issues/1293)
- display\_format: pretty and display\_format: short lead to crash [\#1263](https://github.com/jrnl-org/jrnl/issues/1263)
- Fixed error related to display\_format in config file for some values [\#1495](https://github.com/jrnl-org/jrnl/pull/1495) ([apainintheneck](https://github.com/apainintheneck)) - Fixed error related to display\_format in config file for some values [\#1495](https://github.com/jrnl-org/jrnl/pull/1495) ([apainintheneck](https://github.com/apainintheneck))
- Create folder if config ends with \(back\)slash [\#1492](https://github.com/jrnl-org/jrnl/pull/1492) ([jonakeys](https://github.com/jonakeys)) - Create folder if config ends with \(back\)slash [\#1492](https://github.com/jrnl-org/jrnl/pull/1492) ([jonakeys](https://github.com/jonakeys))
- `-not` search parameter no longer opens editor [\#1490](https://github.com/jrnl-org/jrnl/pull/1490) ([apainintheneck](https://github.com/apainintheneck)) - `-not` search parameter no longer opens editor [\#1490](https://github.com/jrnl-org/jrnl/pull/1490) ([apainintheneck](https://github.com/apainintheneck))
@ -53,12 +36,18 @@
**Deprecated:** **Deprecated:**
- Remove "sample" format and its asteval dependency [\#1435](https://github.com/jrnl-org/jrnl/issues/1435)
- Drop support for Python 3.7 and 3.8 [\#1412](https://github.com/jrnl-org/jrnl/pull/1412) ([micahellison](https://github.com/micahellison)) - Drop support for Python 3.7 and 3.8 [\#1412](https://github.com/jrnl-org/jrnl/pull/1412) ([micahellison](https://github.com/micahellison))
**Build:** **Build:**
- Clean up .gitignore [\#1286](https://github.com/jrnl-org/jrnl/issues/1286) - Pin `pytest-bdd` to \<6.0 to temporarily avoid breaking changes [\#1536](https://github.com/jrnl-org/jrnl/pull/1536) ([wren](https://github.com/wren))
- Reduce difference between local and CI environments [\#1518](https://github.com/jrnl-org/jrnl/pull/1518) ([wren](https://github.com/wren))
- Add bdd tests for jrnl installation [\#1513](https://github.com/jrnl-org/jrnl/pull/1513) ([apainintheneck](https://github.com/apainintheneck))
- Stop hardcoding bot info in changelog pipeline [\#1506](https://github.com/jrnl-org/jrnl/pull/1506) ([wren](https://github.com/wren))
- Fix Poetry caching for accessibility tests [\#1505](https://github.com/jrnl-org/jrnl/pull/1505) ([wren](https://github.com/wren))
- Implement Tox for testing [\#1504](https://github.com/jrnl-org/jrnl/pull/1504) ([wren](https://github.com/wren))
- Replace `make` with python alternative \(`poe`\) [\#1503](https://github.com/jrnl-org/jrnl/pull/1503) ([wren](https://github.com/wren))
- Update copyright year [\#1502](https://github.com/jrnl-org/jrnl/pull/1502) ([wren](https://github.com/wren))
- Add Python 3.11 to PR tests [\#1500](https://github.com/jrnl-org/jrnl/pull/1500) ([micahellison](https://github.com/micahellison)) - Add Python 3.11 to PR tests [\#1500](https://github.com/jrnl-org/jrnl/pull/1500) ([micahellison](https://github.com/micahellison))
- Pin jinja2 in docs requirements to keep readthedocs builds from failing [\#1439](https://github.com/jrnl-org/jrnl/pull/1439) ([micahellison](https://github.com/micahellison)) - Pin jinja2 in docs requirements to keep readthedocs builds from failing [\#1439](https://github.com/jrnl-org/jrnl/pull/1439) ([micahellison](https://github.com/micahellison))
- Tidy up git ignore [\#1414](https://github.com/jrnl-org/jrnl/pull/1414) ([nelnog](https://github.com/nelnog)) - Tidy up git ignore [\#1414](https://github.com/jrnl-org/jrnl/pull/1414) ([nelnog](https://github.com/nelnog))
@ -69,7 +58,8 @@
**Packaging:** **Packaging:**
- Sync jrnl's Python version support more closely to Python release cycle [\#1406](https://github.com/jrnl-org/jrnl/issues/1406) - Bump cryptography from 37.0.2 to 37.0.3 [\#1516](https://github.com/jrnl-org/jrnl/pull/1516) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump poethepoet from 0.13.1 to 0.14.0 [\#1514](https://github.com/jrnl-org/jrnl/pull/1514) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump keyring from 23.5.1 to 23.6.0 [\#1499](https://github.com/jrnl-org/jrnl/pull/1499) ([dependabot[bot]](https://github.com/apps/dependabot)) - Bump keyring from 23.5.1 to 23.6.0 [\#1499](https://github.com/jrnl-org/jrnl/pull/1499) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump pyxdg from 0.27 to 0.28 [\#1497](https://github.com/jrnl-org/jrnl/pull/1497) ([dependabot[bot]](https://github.com/apps/dependabot)) - Bump pyxdg from 0.27 to 0.28 [\#1497](https://github.com/jrnl-org/jrnl/pull/1497) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump keyring from 23.5.0 to 23.5.1 [\#1487](https://github.com/jrnl-org/jrnl/pull/1487) ([dependabot[bot]](https://github.com/apps/dependabot)) - Bump keyring from 23.5.0 to 23.5.1 [\#1487](https://github.com/jrnl-org/jrnl/pull/1487) ([dependabot[bot]](https://github.com/apps/dependabot))

View file

@ -59,7 +59,7 @@ representative at an online or offline event.
## Enforcement ## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by [emailing the maintainers](mailto:jrnl-sh@googlegroups.com). reported by [emailing the maintainers](mailto:maintainers@jrnl.sh).
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

View file

@ -1,6 +1,6 @@
# Security # Security
If you've discovered a potential security issue in jrnl, please contact the maintainers at [jrnl-sh@googlegroups.com](mailto:jrnl-sh@googlegroups.com). If you've discovered a potential security issue in jrnl, please contact the maintainers at [maintainers@jrnl.sh](mailto:maintainers@jrnl.sh).
You can also feel free to [open an issue](https://github.com/jrnl-org/jrnl/issues/new/choose) (but please don't disclose the vulnerability) in case the email goes to spam. You can also feel free to [open an issue](https://github.com/jrnl-org/jrnl/issues/new/choose) (but please don't disclose the vulnerability) in case the email goes to spam.

View file

@ -4,22 +4,22 @@
import datetime import datetime
import fnmatch import fnmatch
import os import os
from pathlib import Path
import platform import platform
import plistlib import plistlib
import re import re
import socket import socket
import time import time
import uuid import uuid
from pathlib import Path
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
import pytz import pytz
import tzlocal import tzlocal
from . import Entry from jrnl import Entry
from . import Journal from jrnl import Journal
from . import __title__ from jrnl import __title__
from . import __version__ from jrnl import __version__
class DayOne(Journal.Journal): class DayOne(Journal.Journal):

View file

@ -18,15 +18,14 @@ from cryptography.hazmat.primitives.ciphers import algorithms
from cryptography.hazmat.primitives.ciphers import modes from cryptography.hazmat.primitives.ciphers import modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from .Journal import Journal
from .Journal import LegacyJournal
from .prompt import create_password
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.Journal import Journal
from jrnl.Journal import LegacyJournal
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg from jrnl.output import print_msg
from jrnl.prompt import create_password
def make_key(password): def make_key(password):

View file

@ -5,8 +5,8 @@ import codecs
import fnmatch import fnmatch
import os import os
from . import Journal from jrnl import Journal
from . import time from jrnl import time
def get_files(journal_config): def get_files(journal_config):

View file

@ -6,15 +6,14 @@ import logging
import os import os
import re import re
from . import Entry from jrnl import Entry
from . import time from jrnl import time
from .prompt import yesno
from .path import expand_path
from jrnl.output import print_msg
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg
from jrnl.path import expand_path
from jrnl.prompt import yesno
class Tag: class Tag:
@ -449,11 +448,11 @@ def open_journal(journal_name, config, legacy=False):
if config["journal"].strip("/").endswith(".dayone") or "entries" in os.listdir( if config["journal"].strip("/").endswith(".dayone") or "entries" in os.listdir(
config["journal"] config["journal"]
): ):
from . import DayOneJournal from jrnl import DayOneJournal
return DayOneJournal.DayOne(**config).open() return DayOneJournal.DayOne(**config).open()
else: else:
from . import FolderJournal from jrnl import FolderJournal
return FolderJournal.Folder(journal_name, **config).open() return FolderJournal.Folder(journal_name, **config).open()
@ -461,12 +460,12 @@ def open_journal(journal_name, config, legacy=False):
if legacy: if legacy:
return LegacyJournal(journal_name, **config).open() return LegacyJournal(journal_name, **config).open()
if config["journal"].endswith(os.sep): if config["journal"].endswith(os.sep):
from . import FolderJournal from jrnl import FolderJournal
return FolderJournal.Folder(journal_name, **config).open() return FolderJournal.Folder(journal_name, **config).open()
return PlainJournal(journal_name, **config).open() return PlainJournal(journal_name, **config).open()
from . import EncryptedJournal from jrnl import EncryptedJournal
if legacy: if legacy:
return EncryptedJournal.LegacyEncryptedJournal(journal_name, **config).open() return EncryptedJournal.LegacyEncryptedJournal(journal_name, **config).open()

View file

@ -2,7 +2,7 @@
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
try: try:
from .__version__ import __version__ from jrnl.__version__ import __version__
except ImportError: except ImportError:
__version__ = "source" __version__ = "source"
__title__ = "jrnl" __title__ = "jrnl"

View file

@ -3,7 +3,7 @@
import sys import sys
from .cli import cli from jrnl.cli import cli
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(cli()) sys.exit(cli())

View file

@ -1 +1 @@
__version__ = "v3.0-beta" __version__ = "v3.0"

View file

@ -5,16 +5,16 @@ import argparse
import re import re
import textwrap import textwrap
from .commands import postconfig_decrypt from jrnl.commands import postconfig_decrypt
from .commands import postconfig_encrypt from jrnl.commands import postconfig_encrypt
from .commands import postconfig_import from jrnl.commands import postconfig_import
from .commands import postconfig_list from jrnl.commands import postconfig_list
from .commands import preconfig_diagnostic from jrnl.commands import preconfig_diagnostic
from .commands import preconfig_version from jrnl.commands import preconfig_version
from .output import deprecated_cmd from jrnl.output import deprecated_cmd
from .plugins import EXPORT_FORMATS from jrnl.plugins import EXPORT_FORMATS
from .plugins import IMPORT_FORMATS from jrnl.plugins import IMPORT_FORMATS
from .plugins import util from jrnl.plugins import util
class WrappingFormatter(argparse.RawTextHelpFormatter): class WrappingFormatter(argparse.RawTextHelpFormatter):

View file

@ -5,14 +5,13 @@ import logging
import sys import sys
import traceback import traceback
from .jrnl import run from jrnl.args import parse_args
from .args import parse_args
from jrnl.output import print_msg
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.jrnl import run
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg
def configure_logger(debug=False): def configure_logger(debug=False):

View file

@ -7,7 +7,7 @@ from string import whitespace
import colorama import colorama
from .os_compat import on_windows from jrnl.os_compat import on_windows
if on_windows(): if on_windows():
colorama.init() colorama.init()

View file

@ -17,11 +17,11 @@ avoid any possible overhead for these standalone commands.
import platform import platform
import sys import sys
from jrnl.output import print_msg
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg
from jrnl.prompt import create_password from jrnl.prompt import create_password
@ -50,14 +50,14 @@ conditions; for details, see: https://www.gnu.org/licenses/gpl-3.0.html"""
def postconfig_list(config, **kwargs): def postconfig_list(config, **kwargs):
from .output import list_journals from jrnl.output import list_journals
print(list_journals(config)) print(list_journals(config))
def postconfig_import(args, config, **kwargs): def postconfig_import(args, config, **kwargs):
from .Journal import open_journal from jrnl.Journal import open_journal
from .plugins import get_importer from jrnl.plugins import get_importer
# Requires opening the journal # Requires opening the journal
journal = open_journal(args.journal_name, config) journal = open_journal(args.journal_name, config)
@ -70,10 +70,10 @@ def postconfig_encrypt(args, config, original_config, **kwargs):
""" """
Encrypt a journal in place, or optionally to a new file Encrypt a journal in place, or optionally to a new file
""" """
from .EncryptedJournal import EncryptedJournal from jrnl.config import update_config
from .Journal import open_journal from jrnl.EncryptedJournal import EncryptedJournal
from .config import update_config from jrnl.install import save_config
from .install import save_config from jrnl.Journal import open_journal
# Open the journal # Open the journal
journal = open_journal(args.journal_name, config) journal = open_journal(args.journal_name, config)
@ -118,10 +118,10 @@ def postconfig_encrypt(args, config, original_config, **kwargs):
def postconfig_decrypt(args, config, original_config, **kwargs): def postconfig_decrypt(args, config, original_config, **kwargs):
"""Decrypts into new file. If filename is not set, we encrypt the journal file itself.""" """Decrypts into new file. If filename is not set, we encrypt the journal file itself."""
from .Journal import PlainJournal from jrnl.config import update_config
from .Journal import open_journal from jrnl.install import save_config
from .config import update_config from jrnl.Journal import PlainJournal
from .install import save_config from jrnl.Journal import open_journal
journal = open_journal(args.journal_name, config) journal = open_journal(args.journal_name, config)
journal.config["encrypt"] = False journal.config["encrypt"] = False

View file

@ -5,18 +5,18 @@ import logging
import os import os
import colorama import colorama
from ruamel.yaml import YAML
import xdg.BaseDirectory import xdg.BaseDirectory
from ruamel.yaml import YAML
from ruamel.yaml import constructor
from . import __version__ from jrnl import __version__
from jrnl.output import list_journals
from jrnl.output import print_msg
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from .path import home_dir from jrnl.output import list_journals
from jrnl.output import print_msg
from jrnl.path import home_dir
# Constants # Constants
DEFAULT_CONFIG_NAME = "jrnl.yaml" DEFAULT_CONFIG_NAME = "jrnl.yaml"
@ -160,10 +160,25 @@ def verify_config_colors(config):
def load_config(config_path): def load_config(config_path):
"""Tries to load a config file from YAML.""" """Tries to load a config file from YAML."""
with open(config_path, encoding=YAML_FILE_ENCODING) as f: try:
yaml = YAML(typ="safe") with open(config_path, encoding=YAML_FILE_ENCODING) as f:
yaml.allow_duplicate_keys = True yaml = YAML(typ="safe")
return yaml.load(f) yaml.allow_duplicate_keys = False
return yaml.load(f)
except constructor.DuplicateKeyError as e:
print_msg(
Message(
MsgText.ConfigDoubleKeys,
MsgStyle.WARNING,
{
"error_message": e,
},
)
)
with open(config_path, encoding=YAML_FILE_ENCODING) as f:
yaml = YAML(typ="safe")
yaml.allow_duplicate_keys = True
return yaml.load(f)
def is_config_json(config_path): def is_config_json(config_path):

View file

@ -8,15 +8,14 @@ import sys
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.os_compat import on_windows from jrnl.os_compat import on_windows
from jrnl.os_compat import split_args from jrnl.os_compat import split_args
from jrnl.output import print_msg from jrnl.output import print_msg
from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle
def get_text_from_editor(config, template=""): def get_text_from_editor(config, template=""):
suffix = ".jrnl" suffix = ".jrnl"
@ -46,7 +45,7 @@ def get_text_from_editor(config, template=""):
os.remove(tmpfile) os.remove(tmpfile)
if not raw: if not raw:
raise JrnlException(Message(MsgText.NoTextReceived, MsgStyle.ERROR)) raise JrnlException(Message(MsgText.NoTextReceived, MsgStyle.NORMAL))
return raw return raw

View file

@ -6,24 +6,23 @@ import logging
import os import os
import sys import sys
from .path import home_dir from jrnl.config import DEFAULT_JOURNAL_KEY
from .path import absolute_path from jrnl.config import get_config_path
from .path import expand_path from jrnl.config import get_default_config
from .config import DEFAULT_JOURNAL_KEY from jrnl.config import get_default_journal_path
from .config import get_config_path from jrnl.config import load_config
from .config import get_default_config from jrnl.config import save_config
from .config import get_default_journal_path from jrnl.config import verify_config_colors
from .config import load_config
from .config import save_config
from .config import verify_config_colors
from .prompt import yesno
from .upgrade import is_old_version
from jrnl.output import print_msg
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg
from jrnl.path import absolute_path
from jrnl.path import expand_path
from jrnl.path import home_dir
from jrnl.prompt import yesno
from jrnl.upgrade import is_old_version
def upgrade_config(config_data, alt_config_path=None): def upgrade_config(config_data, alt_config_path=None):

View file

@ -4,24 +4,23 @@
import logging import logging
import sys import sys
from . import install from jrnl import install
from . import plugins from jrnl import plugins
from .Journal import open_journal from jrnl import time
from .config import get_journal_name from jrnl.config import get_config_path
from .config import scope_config from jrnl.config import get_journal_name
from .config import get_config_path from jrnl.config import scope_config
from .editor import get_text_from_editor from jrnl.editor import get_text_from_editor
from .editor import get_text_from_stdin from jrnl.editor import get_text_from_stdin
from . import time from jrnl.exception import JrnlException
from .override import apply_overrides from jrnl.Journal import open_journal
from jrnl.messages import Message
from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg from jrnl.output import print_msg
from jrnl.output import print_msgs from jrnl.output import print_msgs
from .path import expand_path from jrnl.override import apply_overrides
from jrnl.path import expand_path
from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle
def run(args): def run(args):
@ -141,7 +140,7 @@ def write_mode(args, config, journal, **kwargs):
if not raw or raw.isspace(): if not raw or raw.isspace():
logging.error("Write mode: couldn't get raw text or entry was empty") logging.error("Write mode: couldn't get raw text or entry was empty")
raise JrnlException(Message(MsgText.NoTextReceived, MsgStyle.ERROR)) raise JrnlException(Message(MsgText.NoTextReceived, MsgStyle.NORMAL))
logging.debug( logging.debug(
'Write mode: appending raw text to journal "%s": %s', args.journal_name, raw 'Write mode: appending raw text to journal "%s": %s', args.journal_name, raw
@ -342,6 +341,9 @@ def _print_edited_summary(journal, old_stats, **kwargs):
) )
msgs.append(Message(my_msg, MsgStyle.NORMAL, {"num": stats["modified"]})) msgs.append(Message(my_msg, MsgStyle.NORMAL, {"num": stats["modified"]}))
if not msgs:
msgs.append(Message(MsgText.NoEditsReceived, MsgStyle.NORMAL))
print_msgs(msgs) print_msgs(msgs)

View file

@ -1,11 +1,11 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from typing import NamedTuple
from typing import Mapping from typing import Mapping
from typing import NamedTuple
from .MsgText import MsgText from jrnl.messages.MsgStyle import MsgStyle
from .MsgStyle import MsgStyle from jrnl.messages.MsgText import MsgText
class Message(NamedTuple): class Message(NamedTuple):

View file

@ -2,12 +2,13 @@
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from enum import Enum from enum import Enum
from typing import NamedTuple
from typing import Callable from typing import Callable
from rich.panel import Panel from typing import NamedTuple
from rich import box
from .MsgText import MsgText from rich import box
from rich.panel import Panel
from jrnl.messages.MsgText import MsgText
class MsgStyle(Enum): class MsgStyle(Enum):

View file

@ -149,6 +149,8 @@ class MsgText(Enum):
https://jrnl.sh/en/stable/external-editors/ https://jrnl.sh/en/stable/external-editors/
""" """
NoEditsReceived = "No edits to save, because nothing was changed"
NoTextReceived = """ NoTextReceived = """
No entry to save, because no text was received No entry to save, because no text was received
""" """
@ -196,6 +198,13 @@ class MsgText(Enum):
Configuration updated to newest version at {config_path} Configuration updated to newest version at {config_path}
""" """
ConfigDoubleKeys = """
There is at least one duplicate key in your configuration file.
Details:
{error_message}
"""
# --- Password --- # # --- Password --- #
Password = "Password:" Password = "Password:"
PasswordFirstEntry = "Enter password for journal '{journal_name}': " PasswordFirstEntry = "Enter password for journal '{journal_name}': "

View file

@ -1,9 +1,9 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from .Message import Message from jrnl.messages.Message import Message
from .MsgStyle import MsgStyle from jrnl.messages.MsgStyle import MsgStyle
from .MsgText import MsgText from jrnl.messages.MsgText import MsgText
Message = Message Message = Message
MsgStyle = MsgStyle MsgStyle = MsgStyle

View file

@ -2,10 +2,10 @@
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
import textwrap import textwrap
from typing import Union from typing import Union
from rich.text import Text
from rich.console import Console from rich.console import Console
from rich.text import Text
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
@ -26,7 +26,7 @@ def deprecated_cmd(old_cmd, new_cmd, callback=None, **kwargs):
def list_journals(configuration): def list_journals(configuration):
from . import config from jrnl import config
"""List the journals specified in the configuration file""" """List the journals specified in the configuration file"""
result = f"Journals defined in config ({config.get_config_path()})\n" result = f"Journals defined in config ({config.get_config_path()})\n"
@ -89,5 +89,9 @@ def _add_extra_style_args_if_needed(args, msg):
def format_msg_text(msg: Message) -> Text: def format_msg_text(msg: Message) -> Text:
text = textwrap.dedent(msg.text.value.format(**msg.params)).strip() text = textwrap.dedent(msg.text.value)
text = text.format(**msg.params)
# dedent again in case inserted text needs it
text = textwrap.dedent(text)
text = text.strip()
return Text(text) return Text(text)

View file

@ -1,9 +1,12 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from .config import update_config, make_yaml_valid_dict
from argparse import Namespace from argparse import Namespace
from jrnl.config import make_yaml_valid_dict
from jrnl.config import update_config
# import logging # import logging
def apply_overrides(args: Namespace, base_config: dict) -> dict: def apply_overrides(args: Namespace, base_config: dict) -> dict:
"""Unpack CLI provided overrides into the configuration tree. """Unpack CLI provided overrides into the configuration tree.

View file

@ -1,15 +1,15 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from .fancy_exporter import FancyExporter from jrnl.plugins.dates_exporter import DatesExporter
from .jrnl_importer import JRNLImporter from jrnl.plugins.fancy_exporter import FancyExporter
from .json_exporter import JSONExporter from jrnl.plugins.jrnl_importer import JRNLImporter
from .markdown_exporter import MarkdownExporter from jrnl.plugins.json_exporter import JSONExporter
from .tag_exporter import TagExporter from jrnl.plugins.markdown_exporter import MarkdownExporter
from .dates_exporter import DatesExporter from jrnl.plugins.tag_exporter import TagExporter
from .text_exporter import TextExporter from jrnl.plugins.text_exporter import TextExporter
from .xml_exporter import XMLExporter from jrnl.plugins.xml_exporter import XMLExporter
from .yaml_exporter import YAMLExporter from jrnl.plugins.yaml_exporter import YAMLExporter
__exporters = [ __exporters = [
JSONExporter, JSONExporter,

View file

@ -3,7 +3,7 @@
from collections import Counter from collections import Counter
from .text_exporter import TextExporter from jrnl.plugins.text_exporter import TextExporter
class DatesExporter(TextExporter): class DatesExporter(TextExporter):

View file

@ -1,13 +1,13 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle
from textwrap import TextWrapper from textwrap import TextWrapper
from .text_exporter import TextExporter from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.plugins.text_exporter import TextExporter
class FancyExporter(TextExporter): class FancyExporter(TextExporter):

View file

@ -5,8 +5,8 @@ import sys
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg from jrnl.output import print_msg

View file

@ -3,8 +3,8 @@
import json import json
from .text_exporter import TextExporter from jrnl.plugins.text_exporter import TextExporter
from .util import get_tags_count from jrnl.plugins.util import get_tags_count
class JSONExporter(TextExporter): class JSONExporter(TextExporter):

View file

@ -4,12 +4,11 @@
import os import os
import re import re
from .text_exporter import TextExporter
from jrnl.output import print_msg
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg
from jrnl.plugins.text_exporter import TextExporter
class MarkdownExporter(TextExporter): class MarkdownExporter(TextExporter):

View file

@ -1,8 +1,8 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from .text_exporter import TextExporter from jrnl.plugins.text_exporter import TextExporter
from .util import get_tags_count from jrnl.plugins.util import get_tags_count
class TagExporter(TextExporter): class TagExporter(TextExporter):

View file

@ -5,10 +5,10 @@ import os
import re import re
import unicodedata import unicodedata
from jrnl.output import print_msg
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg
class TextExporter: class TextExporter:

View file

@ -3,8 +3,8 @@
from xml.dom import minidom from xml.dom import minidom
from .json_exporter import JSONExporter from jrnl.plugins.json_exporter import JSONExporter
from .util import get_tags_count from jrnl.plugins.util import get_tags_count
class XMLExporter(JSONExporter): class XMLExporter(JSONExporter):

View file

@ -4,13 +4,12 @@
import os import os
import re import re
from .text_exporter import TextExporter
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg from jrnl.output import print_msg
from jrnl.plugins.text_exporter import TextExporter
class YAMLExporter(TextExporter): class YAMLExporter(TextExporter):

View file

@ -2,8 +2,8 @@
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg from jrnl.output import print_msg
from jrnl.output import print_msgs from jrnl.output import print_msgs
@ -35,7 +35,7 @@ def create_password(journal_name: str) -> str:
print_msg(Message(MsgText.PasswordDidNotMatch, MsgStyle.ERROR)) print_msg(Message(MsgText.PasswordDidNotMatch, MsgStyle.ERROR))
if yesno(Message(MsgText.PasswordStoreInKeychain), default=True): if yesno(Message(MsgText.PasswordStoreInKeychain), default=True):
from .EncryptedJournal import set_keychain from jrnl.EncryptedJournal import set_keychain
set_keychain(journal_name, pw) set_keychain(journal_name, pw)

View file

@ -3,21 +3,20 @@
import os import os
from . import Journal from jrnl import Journal
from . import __version__ from jrnl import __version__
from .EncryptedJournal import EncryptedJournal from jrnl.config import is_config_json
from .config import is_config_json from jrnl.config import load_config
from .config import load_config from jrnl.config import scope_config
from .config import scope_config from jrnl.EncryptedJournal import EncryptedJournal
from .prompt import yesno
from .path import expand_path
from jrnl.output import print_msg
from jrnl.output import print_msgs
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText
from jrnl.output import print_msg
from jrnl.output import print_msgs
from jrnl.path import expand_path
from jrnl.prompt import yesno
def backup(filename, binary=False): def backup(filename, binary=False):

254
poetry.lock generated
View file

@ -44,7 +44,7 @@ test = ["astroid", "pytest"]
[[package]] [[package]]
name = "atomicwrites" name = "atomicwrites"
version = "1.4.0" version = "1.4.1"
description = "Atomic file writes." description = "Atomic file writes."
category = "dev" category = "dev"
optional = false optional = false
@ -74,7 +74,7 @@ python-versions = "*"
[[package]] [[package]]
name = "black" name = "black"
version = "22.3.0" version = "22.6.0"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
category = "dev" category = "dev"
optional = false optional = false
@ -85,7 +85,7 @@ click = ">=8.0.0"
mypy-extensions = ">=0.4.3" mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0" pathspec = ">=0.9.0"
platformdirs = ">=2" platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
[package.extras] [package.extras]
@ -96,7 +96,7 @@ uvloop = ["uvloop (>=0.15.2)"]
[[package]] [[package]]
name = "cffi" name = "cffi"
version = "1.15.0" version = "1.15.1"
description = "Foreign Function Interface for Python calling C code." description = "Foreign Function Interface for Python calling C code."
category = "main" category = "main"
optional = false optional = false
@ -137,7 +137,7 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
[[package]] [[package]]
name = "cryptography" name = "cryptography"
version = "37.0.2" version = "37.0.4"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
category = "main" category = "main"
optional = false optional = false
@ -170,6 +170,17 @@ category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
[[package]]
name = "execnet"
version = "1.9.0"
description = "execnet: rapid multi-Python deployment"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.extras]
testing = ["pre-commit"]
[[package]] [[package]]
name = "executing" name = "executing"
version = "0.8.3" version = "0.8.3"
@ -227,7 +238,7 @@ python-versions = "*"
[[package]] [[package]]
name = "importlib-metadata" name = "importlib-metadata"
version = "4.11.4" version = "4.12.0"
description = "Read metadata from Python packages" description = "Read metadata from Python packages"
category = "main" category = "main"
optional = false optional = false
@ -239,7 +250,7 @@ zipp = ">=0.5"
[package.extras] [package.extras]
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
perf = ["ipython"] perf = ["ipython"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
[[package]] [[package]]
name = "iniconfig" name = "iniconfig"
@ -297,6 +308,20 @@ qtconsole = ["qtconsole"]
test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] test = ["pytest (<7.1)", "pytest-asyncio", "testpath"]
test_extra = ["pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "trio"] test_extra = ["pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "trio"]
[[package]]
name = "isort"
version = "5.10.1"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
python-versions = ">=3.6.1,<4.0"
[package.extras]
pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"]
plugins = ["setuptools"]
[[package]] [[package]]
name = "jedi" name = "jedi"
version = "0.18.1" version = "0.18.1"
@ -358,7 +383,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[[package]] [[package]]
name = "mako" name = "mako"
version = "1.2.0" version = "1.2.1"
description = "A super-fast templating language that borrows the best ideas from the existing templating languages." description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
category = "dev" category = "dev"
optional = false optional = false
@ -568,11 +593,11 @@ testing = ["pytest", "pytest-benchmark"]
[[package]] [[package]]
name = "poethepoet" name = "poethepoet"
version = "0.13.1" version = "0.15.0"
description = "A task runner that works well with poetry." description = "A task runner that works well with poetry."
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.6.2" python-versions = ">=3.7"
[package.dependencies] [package.dependencies]
pastel = ">=0.2.1,<0.3.0" pastel = ">=0.2.1,<0.3.0"
@ -591,7 +616,7 @@ python-versions = "*"
[[package]] [[package]]
name = "prompt-toolkit" name = "prompt-toolkit"
version = "3.0.29" version = "3.0.30"
description = "Library for building powerful interactive command lines in Python" description = "Library for building powerful interactive command lines in Python"
category = "dev" category = "dev"
optional = false optional = false
@ -732,6 +757,36 @@ pprintpp = ">=0.4.0"
pytest = ">=3.5.0" pytest = ">=3.5.0"
rich = ">=8.0.0" rich = ">=8.0.0"
[[package]]
name = "pytest-forked"
version = "1.4.0"
description = "run tests in isolated forked subprocesses"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
py = "*"
pytest = ">=3.10"
[[package]]
name = "pytest-xdist"
version = "2.5.0"
description = "pytest xdist plugin for distributed testing and loop-on-failing modes"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
execnet = ">=1.1"
pytest = ">=6.2.0"
pytest-forked = "*"
[package.extras]
psutil = ["psutil (>=3.0)"]
setproctitle = ["setproctitle"]
testing = ["filelock"]
[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
version = "2.8.2" version = "2.8.2"
@ -886,7 +941,7 @@ python-versions = ">=3.7"
[[package]] [[package]]
name = "tox" name = "tox"
version = "3.25.0" version = "3.25.1"
description = "tox is a generic virtualenv management and test command line tool" description = "tox is a generic virtualenv management and test command line tool"
category = "dev" category = "dev"
optional = false optional = false
@ -919,7 +974,7 @@ test = ["pre-commit", "pytest"]
[[package]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.2.0" version = "4.3.0"
description = "Backported and Experimental Type Hints for Python 3.7+" description = "Backported and Experimental Type Hints for Python 3.7+"
category = "dev" category = "dev"
optional = false optional = false
@ -938,7 +993,7 @@ pytz = "*"
[[package]] [[package]]
name = "virtualenv" name = "virtualenv"
version = "20.14.1" version = "20.15.1"
description = "Virtual Python Environment builder" description = "Virtual Python Environment builder"
category = "dev" category = "dev"
optional = false optional = false
@ -983,7 +1038,7 @@ python-versions = ">=3.4"
[[package]] [[package]]
name = "yq" name = "yq"
version = "2.14.0" version = "3.0.2"
description = "Command-line YAML/XML processor - jq wrapper for YAML/XML documents" description = "Command-line YAML/XML processor - jq wrapper for YAML/XML documents"
category = "dev" category = "dev"
optional = false optional = false
@ -1010,13 +1065,10 @@ python-versions = ">=3.7"
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
[extras]
testing = []
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = ">=3.9.0, <3.12" python-versions = ">=3.9.0, <3.12"
content-hash = "ceca9186ac31a0b8ec81a6cc134469842080c786971bb8642d9e67d51bd73fca" content-hash = "647a60d3f5c77ae365e4acef948b048a112eebd0315e026ffe31a0cc441c6601"
[metadata.files] [metadata.files]
ansiwrap = [ ansiwrap = [
@ -1035,10 +1087,7 @@ asttokens = [
{file = "asttokens-2.0.5-py2.py3-none-any.whl", hash = "sha256:0844691e88552595a6f4a4281a9f7f79b8dd45ca4ccea82e5e05b4bbdb76705c"}, {file = "asttokens-2.0.5-py2.py3-none-any.whl", hash = "sha256:0844691e88552595a6f4a4281a9f7f79b8dd45ca4ccea82e5e05b4bbdb76705c"},
{file = "asttokens-2.0.5.tar.gz", hash = "sha256:9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"}, {file = "asttokens-2.0.5.tar.gz", hash = "sha256:9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"},
] ]
atomicwrites = [ atomicwrites = []
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
]
attrs = [ attrs = [
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
@ -1047,83 +1096,8 @@ backcall = [
{file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
{file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
] ]
black = [ black = []
{file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, cffi = []
{file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"},
{file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"},
{file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"},
{file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"},
{file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"},
{file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"},
{file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"},
{file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"},
{file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"},
{file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"},
{file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"},
{file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"},
{file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"},
{file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"},
{file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"},
{file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"},
{file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"},
{file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"},
{file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"},
{file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"},
{file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"},
{file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"},
]
cffi = [
{file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"},
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"},
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"},
{file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"},
{file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"},
{file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"},
{file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"},
{file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"},
{file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"},
{file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"},
{file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"},
{file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"},
{file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"},
{file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"},
{file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"},
{file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"},
{file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"},
{file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"},
{file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"},
{file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"},
{file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"},
{file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"},
{file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"},
{file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"},
{file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
]
click = [ click = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
@ -1136,30 +1110,7 @@ commonmark = [
{file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
{file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
] ]
cryptography = [ cryptography = []
{file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181"},
{file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3c81599befb4d4f3d7648ed3217e00d21a9341a9a688ecdd615ff72ffbed7336"},
{file = "cryptography-37.0.2-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2bd1096476aaac820426239ab534b636c77d71af66c547b9ddcd76eb9c79e004"},
{file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:31fe38d14d2e5f787e0aecef831457da6cec68e0bb09a35835b0b44ae8b988fe"},
{file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:093cb351031656d3ee2f4fa1be579a8c69c754cf874206be1d4cf3b542042804"},
{file = "cryptography-37.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59b281eab51e1b6b6afa525af2bd93c16d49358404f814fe2c2410058623928c"},
{file = "cryptography-37.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:0cc20f655157d4cfc7bada909dc5cc228211b075ba8407c46467f63597c78178"},
{file = "cryptography-37.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a"},
{file = "cryptography-37.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:46f4c544f6557a2fefa7ac8ac7d1b17bf9b647bd20b16decc8fbcab7117fbc15"},
{file = "cryptography-37.0.2-cp36-abi3-win32.whl", hash = "sha256:731c8abd27693323b348518ed0e0705713a36d79fdbd969ad968fbef0979a7e0"},
{file = "cryptography-37.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:471e0d70201c069f74c837983189949aa0d24bb2d751b57e26e3761f2f782b8d"},
{file = "cryptography-37.0.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a68254dd88021f24a68b613d8c51d5c5e74d735878b9e32cc0adf19d1f10aaf9"},
{file = "cryptography-37.0.2-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:a7d5137e556cc0ea418dca6186deabe9129cee318618eb1ffecbd35bee55ddc1"},
{file = "cryptography-37.0.2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aeaba7b5e756ea52c8861c133c596afe93dd716cbcacae23b80bc238202dc023"},
{file = "cryptography-37.0.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95e590dd70642eb2079d280420a888190aa040ad20f19ec8c6e097e38aa29e06"},
{file = "cryptography-37.0.2-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1b9362d34363f2c71b7853f6251219298124aa4cc2075ae2932e64c91a3e2717"},
{file = "cryptography-37.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e53258e69874a306fcecb88b7534d61820db8a98655662a3dd2ec7f1afd9132f"},
{file = "cryptography-37.0.2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:1f3bfbd611db5cb58ca82f3deb35e83af34bb8cf06043fa61500157d50a70982"},
{file = "cryptography-37.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:419c57d7b63f5ec38b1199a9521d77d7d1754eb97827bbb773162073ccd8c8d4"},
{file = "cryptography-37.0.2-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:dc26bb134452081859aa21d4990474ddb7e863aa39e60d1592800a8865a702de"},
{file = "cryptography-37.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b8398b3d0efc420e777c40c16764d6870bcef2eb383df9c6dbb9ffe12c64452"},
{file = "cryptography-37.0.2.tar.gz", hash = "sha256:f224ad253cc9cea7568f49077007d2263efa57396a2f2f78114066fd54b5c68e"},
]
decorator = [ decorator = [
{file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
{file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
@ -1168,6 +1119,10 @@ distlib = [
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
{file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
] ]
execnet = [
{file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"},
{file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"},
]
executing = [ executing = [
{file = "executing-0.8.3-py2.py3-none-any.whl", hash = "sha256:d1eef132db1b83649a3905ca6dd8897f71ac6f8cac79a7e58a1a09cf137546c9"}, {file = "executing-0.8.3-py2.py3-none-any.whl", hash = "sha256:d1eef132db1b83649a3905ca6dd8897f71ac6f8cac79a7e58a1a09cf137546c9"},
{file = "executing-0.8.3.tar.gz", hash = "sha256:c6554e21c6b060590a6d3be4b82fb78f8f0194d809de5ea7df1c093763311501"}, {file = "executing-0.8.3.tar.gz", hash = "sha256:c6554e21c6b060590a6d3be4b82fb78f8f0194d809de5ea7df1c093763311501"},
@ -1188,8 +1143,8 @@ glob2 = [
{file = "glob2-0.7.tar.gz", hash = "sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c"}, {file = "glob2-0.7.tar.gz", hash = "sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c"},
] ]
importlib-metadata = [ importlib-metadata = [
{file = "importlib_metadata-4.11.4-py3-none-any.whl", hash = "sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"}, {file = "importlib_metadata-4.12.0-py3-none-any.whl", hash = "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"},
{file = "importlib_metadata-4.11.4.tar.gz", hash = "sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700"}, {file = "importlib_metadata-4.12.0.tar.gz", hash = "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670"},
] ]
iniconfig = [ iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
@ -1202,6 +1157,10 @@ ipython = [
{file = "ipython-8.4.0-py3-none-any.whl", hash = "sha256:7ca74052a38fa25fe9bedf52da0be7d3fdd2fb027c3b778ea78dfe8c212937d1"}, {file = "ipython-8.4.0-py3-none-any.whl", hash = "sha256:7ca74052a38fa25fe9bedf52da0be7d3fdd2fb027c3b778ea78dfe8c212937d1"},
{file = "ipython-8.4.0.tar.gz", hash = "sha256:f2db3a10254241d9b447232cec8b424847f338d9d36f9a577a6192c332a46abd"}, {file = "ipython-8.4.0.tar.gz", hash = "sha256:f2db3a10254241d9b447232cec8b424847f338d9d36f9a577a6192c332a46abd"},
] ]
isort = [
{file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
{file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
]
jedi = [ jedi = [
{file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"},
{file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"},
@ -1218,10 +1177,7 @@ keyring = [
{file = "keyring-23.6.0-py3-none-any.whl", hash = "sha256:372ff2fc43ab779e3f87911c26e6c7acc8bb440cbd82683e383ca37594cb0617"}, {file = "keyring-23.6.0-py3-none-any.whl", hash = "sha256:372ff2fc43ab779e3f87911c26e6c7acc8bb440cbd82683e383ca37594cb0617"},
{file = "keyring-23.6.0.tar.gz", hash = "sha256:3ac00c26e4c93739e19103091a9986a9f79665a78cf15a4df1dba7ea9ac8da2f"}, {file = "keyring-23.6.0.tar.gz", hash = "sha256:3ac00c26e4c93739e19103091a9986a9f79665a78cf15a4df1dba7ea9ac8da2f"},
] ]
mako = [ mako = []
{file = "Mako-1.2.0-py3-none-any.whl", hash = "sha256:23aab11fdbbb0f1051b93793a58323ff937e98e34aece1c4219675122e57e4ba"},
{file = "Mako-1.2.0.tar.gz", hash = "sha256:9a7c7e922b87db3686210cf49d5d767033a41d4010b284e747682c92bddd8b39"},
]
markdown = [ markdown = [
{file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"},
{file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"},
@ -1331,18 +1287,12 @@ pluggy = [
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
] ]
poethepoet = [ poethepoet = []
{file = "poethepoet-0.13.1-py3-none-any.whl", hash = "sha256:47e7b38c8b5412f840447f7612a9330697e8633e7500a7340b6734f50e26e380"},
{file = "poethepoet-0.13.1.tar.gz", hash = "sha256:4f6962f17f5d5a453fd7fa66e3e7897e9191d4289148433efe441c81f2451a46"},
]
pprintpp = [ pprintpp = [
{file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"}, {file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"},
{file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"}, {file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"},
] ]
prompt-toolkit = [ prompt-toolkit = []
{file = "prompt_toolkit-3.0.29-py3-none-any.whl", hash = "sha256:62291dad495e665fca0bda814e342c69952086afb0f4094d0893d357e5c78752"},
{file = "prompt_toolkit-3.0.29.tar.gz", hash = "sha256:bd640f60e8cecd74f0dc249713d433ace2ddc62b65ee07f96d358e0b152b6ea7"},
]
ptyprocess = [ ptyprocess = [
{file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
{file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
@ -1390,6 +1340,14 @@ pytest-bdd = [
pytest-clarity = [ pytest-clarity = [
{file = "pytest-clarity-1.0.1.tar.gz", hash = "sha256:505fe345fad4fe11c6a4187fe683f2c7c52c077caa1e135f3e483fe112db7772"}, {file = "pytest-clarity-1.0.1.tar.gz", hash = "sha256:505fe345fad4fe11c6a4187fe683f2c7c52c077caa1e135f3e483fe112db7772"},
] ]
pytest-forked = [
{file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"},
{file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"},
]
pytest-xdist = [
{file = "pytest-xdist-2.5.0.tar.gz", hash = "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf"},
{file = "pytest_xdist-2.5.0-py3-none-any.whl", hash = "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"},
]
python-dateutil = [ python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
@ -1504,26 +1462,17 @@ tomli = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
] ]
tox = [ tox = []
{file = "tox-3.25.0-py2.py3-none-any.whl", hash = "sha256:0805727eb4d6b049de304977dfc9ce315a1938e6619c3ab9f38682bb04662a5a"},
{file = "tox-3.25.0.tar.gz", hash = "sha256:37888f3092aa4e9f835fc8cc6dadbaaa0782651c41ef359e3a5743fcb0308160"},
]
traitlets = [ traitlets = [
{file = "traitlets-5.3.0-py3-none-any.whl", hash = "sha256:65fa18961659635933100db8ca120ef6220555286949774b9cfc106f941d1c7a"}, {file = "traitlets-5.3.0-py3-none-any.whl", hash = "sha256:65fa18961659635933100db8ca120ef6220555286949774b9cfc106f941d1c7a"},
{file = "traitlets-5.3.0.tar.gz", hash = "sha256:0bb9f1f9f017aa8ec187d8b1b2a7a6626a2a1d877116baba52a129bfa124f8e2"}, {file = "traitlets-5.3.0.tar.gz", hash = "sha256:0bb9f1f9f017aa8ec187d8b1b2a7a6626a2a1d877116baba52a129bfa124f8e2"},
] ]
typing-extensions = [ typing-extensions = []
{file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"},
{file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"},
]
tzlocal = [ tzlocal = [
{file = "tzlocal-2.1-py2.py3-none-any.whl", hash = "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4"}, {file = "tzlocal-2.1-py2.py3-none-any.whl", hash = "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4"},
{file = "tzlocal-2.1.tar.gz", hash = "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44"}, {file = "tzlocal-2.1.tar.gz", hash = "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44"},
] ]
virtualenv = [ virtualenv = []
{file = "virtualenv-20.14.1-py2.py3-none-any.whl", hash = "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a"},
{file = "virtualenv-20.14.1.tar.gz", hash = "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5"},
]
watchdog = [ watchdog = [
{file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330"}, {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330"},
{file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d"}, {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d"},
@ -1559,10 +1508,7 @@ xmltodict = [
{file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"},
{file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"},
] ]
yq = [ yq = []
{file = "yq-2.14.0-py3-none-any.whl", hash = "sha256:b6321b29cb39c4e92a4a6f16d47d99a024650211e45e09a02d1906ec45fbaede"},
{file = "yq-2.14.0.tar.gz", hash = "sha256:f4bf2b299d1e5c7ebd74cfb25d1f5d9b6401063bac07a2d09a156144c1d644e1"},
]
zipp = [ zipp = [
{file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"},
{file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"},

View file

@ -1,15 +1,15 @@
[tool.poetry] [tool.poetry]
name = "jrnl" name = "jrnl"
version = "v3.0-beta" version = "v3.0"
description = "Collect your thoughts and notes without leaving the command line." description = "Collect your thoughts and notes without leaving the command line."
authors = [ authors = [
"jrnl contributors <jrnl-sh@googlegroups.com>", "jrnl contributors <maintainers@jrnl.sh>",
"Manuel Ebert <manuel@1450.me>", "Manuel Ebert <manuel@1450.me>",
"Jonathan Wren <jonathan@nowandwren.com>", "Jonathan Wren <jonathan@nowandwren.com>",
"Micah Ellison <micahellison@gmail.com>" "Micah Ellison <micahellison@gmail.com>"
] ]
maintainers = [ maintainers = [
"Jonathan Wren and Micah Ellison <jrnl-sh@googlegroups.com>", "Jonathan Wren and Micah Ellison <maintainers@jrnl.sh>",
] ]
license = "GPL-3.0-only" license = "GPL-3.0-only"
readme = "README.md" readme = "README.md"
@ -44,73 +44,75 @@ pytz = ">=2020" # https://pythonhosted.org/pytz/#issues-limitations
tzlocal = ">2.0, <3.0" # https://github.com/regebro/tzlocal/blob/master/CHANGES.txt tzlocal = ">2.0, <3.0" # https://github.com/regebro/tzlocal/blob/master/CHANGES.txt
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
mkdocs = ">=1.0,<1.3"
black = { version = ">=21.5b2", allow-prereleases = true } black = { version = ">=21.5b2", allow-prereleases = true }
toml = ">=0.10"
pytest = ">=6.2"
pytest-bdd = ">=4.0.1"
ipdb = "*" ipdb = "*"
isort = ">=5.10"
mkdocs = ">=1.0,<1.3"
poethepoet = "*" poethepoet = "*"
pytest-clarity = "*"
pyproject-flake8 = "*" pyproject-flake8 = "*"
yq = "*" pytest = ">=6.2"
pytest-bdd = ">=4.0.1,<6.0"
pytest-clarity = "*"
pytest-xdist = ">=2.5.0"
toml = ">=0.10"
tox = "*" tox = "*"
yq = "*"
[tool.poetry.extras]
testing = [ "pytest", "pytest-bdd", "toml" ]
[tool.poetry.scripts] [tool.poetry.scripts]
jrnl = 'jrnl.cli:cli' jrnl = 'jrnl.cli:cli'
[tool.poe.tasks] [tool.poe.tasks]
format = "black ." format-run = [
format-check = "black --check --diff ." {cmd = "black ."},
format-version = "black --version" ]
format-check = [
{cmd = "black --version"},
{cmd = "black --check --diff ."},
]
style-check = [
{cmd = "pflake8 --version"},
{cmd = "pflake8 jrnl tests"},
]
sort-run = [
{cmd = "isort ."},
]
sort-check = [
{cmd = "isort --version"},
{cmd = "isort --check ."},
]
# docs-check = ?
docs-run = [
{cmd = "mkdocs serve"},
]
test-run =[
{cmd = "tox -q -e py --"},
]
style-check = "pflake8 jrnl tests" installer-check = [
style-version = "pflake8 --version" {cmd = "poetry --version"},
{cmd = "poetry check"},
docs = "mkdocs serve" ]
test-unit = "tox -q -e unit --"
test-bdd = "tox -q -e bdd --"
test-all = "tox -e py --"
installer-check = "poetry check"
installer-version = "poetry --version"
# Groups of tasks # Groups of tasks
format = [
"format-run",
"sort-run",
]
lint = [ lint = [
"installer-check", "installer-check",
"style-check", "style-check",
"sort-check",
"format-check", "format-check",
] ]
test = [ test = [
"lint", "lint",
"test-unit", "test-run",
"test-bdd",
]
ci-lint = [
"installer-version",
"installer-check",
"style-version",
"style-check",
"format-version",
"format-check",
]
ci-test = [
"test-all",
] ]
[tool.isort] [tool.isort]
multi_line_output = 7 profile = "black"
force_single_line = true force_single_line = true
line_length = 88 known_first_party = ["jrnl", "tests"]
known_first_party = ["jrnl"]
force_sort_within_sections = true
[tool.pytest.ini_options] [tool.pytest.ini_options]
minversion = "6.0" minversion = "6.0"
@ -125,7 +127,9 @@ markers = [
"on_posix", "on_posix",
] ]
addopts = [ addopts = [
"--pdbcls=IPython.terminal.debugger:Pdb" "--pdbcls=IPython.terminal.debugger:Pdb",
"--tb=native",
"-n=auto",
] ]
filterwarnings = [ filterwarnings = [
@ -147,21 +151,16 @@ build-backend = "poetry.core.masonry.api"
# see: https://tox.wiki/en/latest/example/basic.html # see: https://tox.wiki/en/latest/example/basic.html
legacy_tox_ini = """ legacy_tox_ini = """
[tox] [tox]
envlist = py-{unit,bdd} envlist = py
isolated_build = True isolated_build = True
[testenv] [testenv]
deps = deps =
pytest >= 6.2 pytest >= 6.2
pytest-bdd >=4.0.1 pytest-bdd >=4.0.1,<6.0
pytest-xdist >=2.5.0
toml >=0.10 toml >=0.10
commands = pytest --junitxml=reports/pytest/results.xml {posargs}
commands = pytest {posargs}
passenv = HOME passenv = HOME
[testenv:unit]
commands = pytest tests/unit {posargs}
[testenv:bdd]
commands = pytest tests/bdd --gherkin-terminal-reporter --tb=native {posargs}
""" """

View file

@ -111,3 +111,19 @@ Feature: Multiple journals
Given we use the config "linewrap_auto.yaml" Given we use the config "linewrap_auto.yaml"
When we run "jrnl -1" When we run "jrnl -1"
Then the output should contain "Life is good." Then the output should contain "Life is good."
Scenario: Show a warning message when the config file contains duplicate keys at the same level
Given the config "duplicate_keys.yaml" exists
And we use the config "duplicate_keys.yaml"
When we run "jrnl -1"
Then the output should contain "There is at least one duplicate key in your configuration file"
Scenario: Show a warning message when using --config-file with duplicate keys
Given the config "duplicate_keys.yaml" exists
And we use the config "multiple.yaml"
When we run "jrnl --cf duplicate_keys.yaml -1"
Then the output should contain "There is at least one duplicate key in your configuration file"
Scenario: Don't show a duplicate keys warning message when using --config-override on an existing value
Given we use the config "multiple.yaml"
When we run "jrnl --config-override highlight false"
Then the output should not contain "There is at least one duplicate key in your configuration file"

View file

@ -0,0 +1,45 @@
Feature: Installing jrnl
Scenario: Install jrnl with default options
Given we use no config
When we run "jrnl hello world" and enter
\n
\n
Then the output should contain "Journal 'default' created"
And the default journal "journal.txt" should be in the "." directory
And the config should contain "encrypt: false"
And the version in the config file should be up-to-date
Scenario: Install jrnl with custom relative default journal path
Given we use no config
When we run "jrnl hello world" and enter
default/custom.txt
n
Then the output should contain "Journal 'default' created"
And the default journal "custom.txt" should be in the "default" directory
And the config should contain "encrypt: false"
And the version in the config file should be up-to-date
Scenario: Install jrnl with custom expanded default journal path
Given we use no config
And the home directory is called "home"
When we run "jrnl hello world" and enter
~/custom.txt
n
Then the output should contain "Journal 'default' created"
And the default journal "custom.txt" should be in the "home" directory
And the config should contain "encrypt: false"
And the version in the config file should be up-to-date
Scenario: Install jrnl with encrypted default journal
Given we use no config
When we run "jrnl hello world" and enter
encrypted.txt
y
Then the output should contain "Journal will be encrypted"
And the default journal "encrypted.txt" should be in the "." directory
And the config should contain "encrypt: true"
And the version in the config file should be up-to-date
When we run "jrnl"
Then we should be prompted for a password

View file

@ -13,6 +13,7 @@ scenarios("features/encrypt.feature")
scenarios("features/file_storage.feature") scenarios("features/file_storage.feature")
scenarios("features/format.feature") scenarios("features/format.feature")
scenarios("features/import.feature") scenarios("features/import.feature")
scenarios("features/install.feature")
scenarios("features/multiple_journals.feature") scenarios("features/multiple_journals.feature")
scenarios("features/override.feature") scenarios("features/override.feature")
scenarios("features/password.feature") scenarios("features/password.feature")

View file

@ -4,9 +4,8 @@
from pytest import mark from pytest import mark
from pytest import skip from pytest import skip
from jrnl.os_compat import on_windows
from jrnl.os_compat import on_posix from jrnl.os_compat import on_posix
from jrnl.os_compat import on_windows
pytest_plugins = [ pytest_plugins = [
"tests.lib.fixtures", "tests.lib.fixtures",

View file

@ -0,0 +1,27 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
template: false
template: false
journals:
default:
encrypt: false
journal: features/journals/simple.journal
journal: features/journals/simple.journal
ideas:
encrypt: false
journal: features/journals/does-not-exist.journal
simple:
encrypt: false
journal: features/journals/simple.journal
encrypt: false
work:
encrypt: false
journal: features/journals/work.journal
linewrap: 80
tagsymbols: '@'
editor: nano
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -1,23 +1,23 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from collections import defaultdict
import os import os
from pathlib import Path
import tempfile import tempfile
from collections import defaultdict
from collections.abc import Iterable from collections.abc import Iterable
from pathlib import Path
from unittest.mock import Mock
from unittest.mock import patch
import toml
from keyring import backend from keyring import backend
from keyring import errors from keyring import errors
from pytest import fixture from pytest import fixture
from unittest.mock import patch
from unittest.mock import Mock
from .helpers import get_fixture
import toml
from rich.console import Console from rich.console import Console
from jrnl.config import load_config from jrnl.config import load_config
from jrnl.os_compat import split_args from jrnl.os_compat import split_args
from tests.lib.helpers import get_fixture
# --- Keyring --- # # --- Keyring --- #
@ -88,6 +88,7 @@ def cli_run(
mock_editor, mock_editor,
mock_user_input, mock_user_input,
mock_overrides, mock_overrides,
mock_default_journal_path,
): ):
# Check if we need more mocks # Check if we need more mocks
mock_factories.update(mock_args) mock_factories.update(mock_args)
@ -96,6 +97,7 @@ def cli_run(
mock_factories.update(mock_editor) mock_factories.update(mock_editor)
mock_factories.update(mock_config_path) mock_factories.update(mock_config_path)
mock_factories.update(mock_user_input) mock_factories.update(mock_user_input)
mock_factories.update(mock_default_journal_path)
return { return {
"status": 0, "status": 0,
@ -164,6 +166,19 @@ def mock_config_path(request):
} }
@fixture
def mock_default_journal_path(temp_dir):
journal_path = os.path.join(temp_dir.name, "journal.txt")
return {
"default_journal_path_install": lambda: patch(
"jrnl.install.get_default_journal_path", return_value=journal_path
),
"default_journal_path_config": lambda: patch(
"jrnl.config.get_default_journal_path", return_value=journal_path
),
}
@fixture @fixture
def temp_dir(): def temp_dir():
return tempfile.TemporaryDirectory() return tempfile.TemporaryDirectory()
@ -216,7 +231,9 @@ def mock_user_input(request, password_input, stdin_input):
return password_input return password_input
if isinstance(user_input, Iterable): if isinstance(user_input, Iterable):
return next(user_input) input_line = next(user_input)
# A raw newline is used to indicate deliberate empty input
return "" if input_line == r"\n" else input_line
# exceptions # exceptions
return user_input if not kwargs["password"] else password_input return user_input if not kwargs["password"] else password_input

View file

@ -1,12 +1,12 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from datetime import datetime
import json import json
import os import os
import random import random
import shutil import shutil
import string import string
from datetime import datetime
from unittest.mock import MagicMock from unittest.mock import MagicMock
from unittest.mock import patch from unittest.mock import patch
from xml.etree import ElementTree from xml.etree import ElementTree
@ -16,10 +16,9 @@ from pytest_bdd.parsers import parse
from jrnl import __version__ from jrnl import __version__
from jrnl.time import __get_pdt_calendar from jrnl.time import __get_pdt_calendar
from tests.lib.fixtures import FailedKeyring
from .fixtures import FailedKeyring from tests.lib.fixtures import TestKeyring
from .fixtures import TestKeyring from tests.lib.helpers import get_fixture
from .helpers import get_fixture
@given(parse("we {editor_method} to the editor if opened\n{editor_input}")) @given(parse("we {editor_method} to the editor if opened\n{editor_input}"))
@ -147,3 +146,10 @@ def parse_output_as_language(cli_run, language_name):
assert False, f"Language name {language_name} not recognized" assert False, f"Language name {language_name} not recognized"
return {"lang": language_name, "obj": parsed_output} return {"lang": language_name, "obj": parsed_output}
@given(parse('the home directory is called "{home_dir}"'))
def home_directory(temp_dir, home_dir, monkeypatch):
home_path = os.path.join(temp_dir.name, home_dir)
monkeypatch.setenv("USERPROFILE", home_path) # for windows
monkeypatch.setenv("HOME", home_path) # for *nix

View file

@ -11,11 +11,10 @@ from pytest_bdd.parsers import parse
from ruamel.yaml import YAML from ruamel.yaml import YAML
from jrnl.config import scope_config from jrnl.config import scope_config
from tests.lib.helpers import assert_equal_tags_ignoring_order
from .helpers import assert_equal_tags_ignoring_order from tests.lib.helpers import does_directory_contain_files
from .helpers import does_directory_contain_files from tests.lib.helpers import get_nested_val
from .helpers import parse_should_or_should_not from tests.lib.helpers import parse_should_or_should_not
from .helpers import get_nested_val
@then("we should get no error") @then("we should get no error")
@ -97,6 +96,12 @@ def output_should_contain_version(cli_run, toml_version):
assert toml_version in out, toml_version assert toml_version in out, toml_version
@then("the version in the config file should be up-to-date")
def config_file_version(config_on_disk, toml_version):
config_version = config_on_disk["version"]
assert config_version == toml_version
@then(parse("the output should be {width:d} columns wide")) @then(parse("the output should be {width:d} columns wide"))
def output_should_be_columns_wide(cli_run, width): def output_should_be_columns_wide(cli_run, width):
out = cli_run["stdout"] out = cli_run["stdout"]
@ -105,6 +110,22 @@ def output_should_be_columns_wide(cli_run, width):
assert len(line) <= width assert len(line) <= width
@then(
parse(
'the default journal "{journal_file}" should be in the "{journal_dir}" directory'
)
)
def default_journal_location(journal_file, journal_dir, config_on_disk, temp_dir):
default_journal_path = config_on_disk["journals"]["default"]
expected_journal_path = (
os.path.join(temp_dir.name, journal_file)
if journal_dir == "."
else os.path.join(temp_dir.name, journal_dir, journal_file)
)
# Use os.path.samefile here because both paths might not be fully expanded.
assert os.path.samefile(default_journal_path, expected_journal_path)
@then( @then(
parse( parse(
'the config for journal "{journal_name}" {should_or_should_not} contain "{some_yaml}"' 'the config for journal "{journal_name}" {should_or_should_not} contain "{some_yaml}"'

View file

@ -1,8 +1,8 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from contextlib import ExitStack
import os import os
from contextlib import ExitStack
from pytest_bdd import when from pytest_bdd import when
from pytest_bdd.parsers import parse from pytest_bdd.parsers import parse
@ -23,6 +23,8 @@ def when_we_change_directory(directory_name):
command = '(?P<command>[^"]*)' command = '(?P<command>[^"]*)'
input_method = "(?P<input_method>enter|pipe|type)" input_method = "(?P<input_method>enter|pipe|type)"
all_input = '("(?P<all_input>[^"]*)")' all_input = '("(?P<all_input>[^"]*)")'
# Note: A line with only a raw newline r'\n' is treated as
# an empty line of input internally for testing purposes.
@when(parse('we run "jrnl {command}" and {input_method}\n{all_input}')) @when(parse('we run "jrnl {command}" and {input_method}\n{all_input}'))

View file

@ -1,9 +1,9 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
import pytest
from colorama import Fore from colorama import Fore
from colorama import Style from colorama import Style
import pytest
from jrnl.color import colorize from jrnl.color import colorize

View file

@ -1,11 +1,12 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
import pytest
import os import os
from jrnl.install import find_alt_config import pytest
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.install import find_alt_config
def test_find_alt_config(request): def test_find_alt_config(request):

View file

@ -1,15 +1,15 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
import random
import string
from unittest import mock from unittest import mock
import pytest import pytest
import random
import string
import jrnl import jrnl
from jrnl.jrnl import _display_search_results
from jrnl.args import parse_args from jrnl.args import parse_args
from jrnl.jrnl import _display_search_results
@pytest.fixture @pytest.fixture

View file

@ -1,6 +1,8 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
from argparse import Namespace
import pytest import pytest
from jrnl.override import _convert_dots_to_list from jrnl.override import _convert_dots_to_list
@ -9,8 +11,6 @@ from jrnl.override import _get_key_and_value_from_pair
from jrnl.override import _recursively_apply from jrnl.override import _recursively_apply
from jrnl.override import apply_overrides from jrnl.override import apply_overrides
from argparse import Namespace
@pytest.fixture() @pytest.fixture()
def minimal_config(): def minimal_config():

View file

@ -1,16 +1,16 @@
# Copyright (C) 2012-2022 jrnl contributors # Copyright (C) 2012-2022 jrnl contributors
# License: https://www.gnu.org/licenses/gpl-3.0.html # License: https://www.gnu.org/licenses/gpl-3.0.html
import pytest
import random import random
import string import string
from os import getenv from os import getenv
from unittest.mock import patch from unittest.mock import patch
from jrnl.path import home_dir import pytest
from jrnl.path import expand_path
from jrnl.path import absolute_path from jrnl.path import absolute_path
from jrnl.path import expand_path
from jrnl.path import home_dir
@pytest.fixture @pytest.fixture