diff --git a/CHANGELOG.md b/CHANGELOG.md index 92724355..9ec50c1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,21 @@ # Changelog -## [Unreleased](https://github.com/jrnl-org/jrnl/) +## [v3.3](https://pypi.org/project/jrnl/v3.3/) (2022-10-29) -[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.2...HEAD) +[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.3-beta2...v3.3) **Implemented enhancements:** -- Add dependency security checks in CI [\#1488](https://github.com/jrnl-org/jrnl/issues/1488) -- Add machine-readable format for --list [\#1445](https://github.com/jrnl-org/jrnl/issues/1445) +- Change default config to use journal key [\#1594](https://github.com/jrnl-org/jrnl/pull/1594) ([micahellison](https://github.com/micahellison)) - Add machine readable --list output [\#1592](https://github.com/jrnl-org/jrnl/pull/1592) ([apainintheneck](https://github.com/apainintheneck)) **Fixed bugs:** -- Bug Report - Sometimes jrnl crashes and truncates journal file [\#1599](https://github.com/jrnl-org/jrnl/issues/1599) +- Fix bug for new `--list --format` options when no default journal is specified [\#1621](https://github.com/jrnl-org/jrnl/pull/1621) ([wren](https://github.com/wren)) +- Don't create empty file when attempting a YAML export to a non-existing folder [\#1600](https://github.com/jrnl-org/jrnl/pull/1600) ([outa](https://github.com/outa)) **Build:** -- Replace Dependabot [\#1560](https://github.com/jrnl-org/jrnl/issues/1560) - Update `.gitignore` [\#1604](https://github.com/jrnl-org/jrnl/pull/1604) ([wren](https://github.com/wren)) - Fix Docs Accessibility Testing [\#1588](https://github.com/jrnl-org/jrnl/pull/1588) ([wren](https://github.com/wren)) - Update to use renamed flag for `brew bump-formula-pr` [\#1587](https://github.com/jrnl-org/jrnl/pull/1587) ([wren](https://github.com/wren)) @@ -28,8 +27,9 @@ **Documentation:** -- \[Documentation\] Edit on Github link broken [\#1601](https://github.com/jrnl-org/jrnl/issues/1601) -- Update `--format yaml` example in docs [\#1525](https://github.com/jrnl-org/jrnl/issues/1525) +- Add documentation about how the editor must be a blocking process [\#1456](https://github.com/jrnl-org/jrnl/issues/1456) +- Document that editors must be blocking processes [\#1624](https://github.com/jrnl-org/jrnl/pull/1624) ([micahellison](https://github.com/micahellison)) +- Remove wrong option in configuration file reference [\#1618](https://github.com/jrnl-org/jrnl/pull/1618) ([DSiekmeier](https://github.com/DSiekmeier)) - Update YAML export description in docs [\#1591](https://github.com/jrnl-org/jrnl/pull/1591) ([apainintheneck](https://github.com/apainintheneck)) - Update dependency jinja2 to v3.1.2 [\#1579](https://github.com/jrnl-org/jrnl/pull/1579) ([renovate[bot]](https://github.com/apps/renovate)) - Update dependency typed.js to v2.0.12 [\#1578](https://github.com/jrnl-org/jrnl/pull/1578) ([renovate[bot]](https://github.com/apps/renovate)) @@ -95,6 +95,8 @@ [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v3.0-beta2...v3.0) +🚨 **BREAKING CHANGES** 🚨 + **Implemented enhancements:** - Show name of journal when creating a password/encrypting [\#1478](https://github.com/jrnl-org/jrnl/pull/1478) ([jonakeys](https://github.com/jonakeys)) diff --git a/docs/encryption.md b/docs/encryption.md index 31f64502..6dae9a48 100644 --- a/docs/encryption.md +++ b/docs/encryption.md @@ -140,7 +140,6 @@ import argparse from Crypto.Cipher import AES import getpass import hashlib -import sys parser = argparse.ArgumentParser() parser.add_argument("filepath", help="journal file to decrypt") diff --git a/docs/external-editors.md b/docs/external-editors.md index be321bab..4e8f70b7 100644 --- a/docs/external-editors.md +++ b/docs/external-editors.md @@ -8,11 +8,13 @@ License: https://www.gnu.org/licenses/gpl-3.0.html Configure your preferred external editor by updating the `editor` option in your [configuration file](./reference-config-file.md#editor) +If your editor is not in your operating system's `PATH` environment variable, +then you will have to enter in the full path of your editor. + !!! note To save and log any entry edits, save and close the file. -If your editor is not in your operating system's `PATH` environment variable, -then you will have to enter in the full path of your editor. +All editors must be [blocking processes](https://en.wikipedia.org/wiki/Blocking_(computing)) to work with jrnl. Some editors, such as [micro](https://micro-editor.github.io/), are blocking by default, though others can be made to block with additional arguments, such as many of those documented below. If jrnl opens your editor but finishes running immediately, then your editor is not a blocking process, and you may be able to correct that with one of the suggestions below. ## Sublime Text diff --git a/docs/overview.md b/docs/overview.md index df09d273..5ab25c1a 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -39,7 +39,7 @@ read them or edit them. `jrnl` plays nicely with your favorite text editor. You may prefer to write journal entries in an editor. Or you may want to make changes that require a more comprehensive application. `jrnl` can filter specific entries and pass them -to the external editor of your choice. +to the [external editor](./external-editors.md) of your choice. ## Encryption diff --git a/docs/reference-config-file.md b/docs/reference-config-file.md index 5239daa8..1c58a3a2 100644 --- a/docs/reference-config-file.md +++ b/docs/reference-config-file.md @@ -47,10 +47,11 @@ key will be used instead. If set, executes this command to launch an external editor for writing and editing your entries. The path to a temporary file is passed after it, and `jrnl` processes the file once -the editor is closed. +the editor returns control to `jrnl`. -Some editors require special options to work properly. See -[External Editors](external-editors.md) for details. +Some editors require special options to work properly, since they must be +blocking processes to work with `jrnl`. See [External Editors](external-editors.md) +for details. ### encrypt If `true`, encrypts your journal using AES. Do not change this @@ -90,9 +91,6 @@ See the [python docs](http://docs.python.org/library/time.html#time.strftime) fo Do not change this for an existing journal, since that might lead to data loss. -If you would just like to change how `jrnl` displays dates, -use display_format instead. - !!! note `jrnl` doesn't support the `%z` or `%Z` time zone identifiers. diff --git a/jrnl/Journal.py b/jrnl/Journal.py index c2c43142..2fa1d465 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -8,6 +8,7 @@ import re from jrnl import Entry from jrnl import time +from jrnl.config import validate_journal_name from jrnl.messages import Message from jrnl.messages import MsgStyle from jrnl.messages import MsgText @@ -430,6 +431,7 @@ def open_journal(journal_name, config, legacy=False): If legacy is True, it will open Journals with legacy classes build for backwards compatibility with jrnl 1.x """ + validate_journal_name(journal_name, config) config = config.copy() config["journal"] = expand_path(config["journal"]) diff --git a/jrnl/__version__.py b/jrnl/__version__.py index 9c1e3fb9..3d0bbe9b 100644 --- a/jrnl/__version__.py +++ b/jrnl/__version__.py @@ -1 +1 @@ -__version__ = "v3.2" +__version__ = "v3.3" diff --git a/jrnl/commands.py b/jrnl/commands.py index 6100422b..b1fc81e0 100644 --- a/jrnl/commands.py +++ b/jrnl/commands.py @@ -14,9 +14,11 @@ run. Also, please note that all (non-builtin) imports should be scoped to each function to avoid any possible overhead for these standalone commands. """ +import argparse import platform import sys +from jrnl.config import cmd_requires_valid_journal_name from jrnl.exception import JrnlException from jrnl.messages import Message from jrnl.messages import MsgStyle @@ -56,13 +58,16 @@ def preconfig_version(_): print(output) -def postconfig_list(args, config, **kwargs): +def postconfig_list(args: argparse.Namespace, config: dict, **_) -> int: from jrnl.output import list_journals print(list_journals(config, args.export)) + return 0 -def postconfig_import(args, config, **kwargs): + +@cmd_requires_valid_journal_name +def postconfig_import(args: argparse.Namespace, config: dict, **_) -> int: from jrnl.Journal import open_journal from jrnl.plugins import get_importer @@ -72,8 +77,13 @@ def postconfig_import(args, config, **kwargs): format = args.export if args.export else "jrnl" get_importer(format).import_(journal, args.filename) + return 0 -def postconfig_encrypt(args, config, original_config, **kwargs): + +@cmd_requires_valid_journal_name +def postconfig_encrypt( + args: argparse.Namespace, config: dict, original_config: dict +) -> int: """ Encrypt a journal in place, or optionally to a new file """ @@ -122,8 +132,13 @@ def postconfig_encrypt(args, config, original_config, **kwargs): ) save_config(original_config) + return 0 -def postconfig_decrypt(args, config, original_config, **kwargs): + +@cmd_requires_valid_journal_name +def postconfig_decrypt( + args: argparse.Namespace, config: dict, original_config: dict +) -> int: """Decrypts into new file. If filename is not set, we encrypt the journal file itself.""" from jrnl.config import update_config from jrnl.install import save_config @@ -149,3 +164,5 @@ def postconfig_decrypt(args, config, original_config, **kwargs): original_config, {"encrypt": False}, args.journal_name, force_local=True ) save_config(original_config) + + return 0 diff --git a/jrnl/config.py b/jrnl/config.py index c8d5902c..8e5c5a14 100644 --- a/jrnl/config.py +++ b/jrnl/config.py @@ -1,8 +1,10 @@ # Copyright © 2012-2022 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html +import argparse import logging import os +from typing import Callable import colorama import xdg.BaseDirectory @@ -91,7 +93,7 @@ def get_config_path(): def get_default_config(): return { "version": __version__, - "journals": {"default": get_default_journal_path()}, + "journals": {"default": {"journal": get_default_journal_path()}}, "editor": os.getenv("VISUAL") or os.getenv("EDITOR") or "", "encrypt": False, "template": False, @@ -213,14 +215,27 @@ def get_journal_name(args, config): args.journal_name = potential_journal_name args.text = args.text[1:] - if args.journal_name not in config["journals"]: - raise JrnlException( - Message( - MsgText.NoDefaultJournal, - MsgStyle.ERROR, - {"journals": list_journals(config)}, - ), - ) - logging.debug("Using journal name: %s", args.journal_name) return args + + +def cmd_requires_valid_journal_name(func: Callable) -> Callable: + def wrapper(args: argparse.Namespace, config: dict, original_config: dict): + validate_journal_name(args.journal_name, config) + func(args=args, config=config, original_config=original_config) + + return wrapper + + +def validate_journal_name(journal_name: str, config: dict) -> None: + if journal_name not in config["journals"]: + raise JrnlException( + Message( + MsgText.NoNamedJournal, + MsgStyle.ERROR, + { + "journal_name": journal_name, + "journals": list_journals(config), + }, + ), + ) diff --git a/jrnl/install.py b/jrnl/install.py index a4797dc7..b20685f0 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -122,10 +122,10 @@ def install(): ) journal_path = absolute_path(user_given_path or default_journal_path) default_config = get_default_config() - default_config["journals"][DEFAULT_JOURNAL_KEY] = journal_path + default_config["journals"][DEFAULT_JOURNAL_KEY]["journal"] = journal_path # If the folder doesn't exist, create it - path = os.path.split(default_config["journals"][DEFAULT_JOURNAL_KEY])[0] + path = os.path.split(journal_path)[0] try: os.makedirs(path) except OSError: diff --git a/jrnl/messages/MsgText.py b/jrnl/messages/MsgText.py index 0f509645..b3cc50e7 100644 --- a/jrnl/messages/MsgText.py +++ b/jrnl/messages/MsgText.py @@ -101,7 +101,7 @@ class MsgText(Enum): {template} """ - NoDefaultJournal = "No default journal configured\n{journals}" + NoNamedJournal = "No '{journal_name}' journal configured\n{journals}" DoesNotExist = "{name} does not exist" diff --git a/jrnl/plugins/text_exporter.py b/jrnl/plugins/text_exporter.py index 931305ef..4451cfef 100644 --- a/jrnl/plugins/text_exporter.py +++ b/jrnl/plugins/text_exporter.py @@ -31,18 +31,19 @@ class TextExporter: @classmethod def write_file(cls, journal, path): """Exports a journal into a single file.""" + export_str = cls.export_journal(journal) with open(path, "w", encoding="utf-8") as f: - f.write(cls.export_journal(journal)) - print_msg( - Message( - MsgText.JournalExportedTo, - MsgStyle.NORMAL, - { - "path": path, - }, - ) + f.write(export_str) + print_msg( + Message( + MsgText.JournalExportedTo, + MsgStyle.NORMAL, + { + "path": path, + }, ) - return "" + ) + return "" @classmethod def make_filename(cls, entry): diff --git a/poetry.lock b/poetry.lock index f2662d7e..eda94884 100644 --- a/poetry.lock +++ b/poetry.lock @@ -51,7 +51,7 @@ python-versions = ">=3.5" dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "backcall" @@ -75,6 +75,7 @@ mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -110,7 +111,7 @@ optional = false python-versions = ">=3.6.0" [package.extras] -unicode-backport = ["unicodedata2"] +unicode_backport = ["unicodedata2"] [[package]] name = "click" @@ -177,6 +178,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "entrypoints" +version = "0.4" +description = "Discover and load entry points from installed packages." +category = "dev" +optional = false +python-versions = ">=3.6" + [[package]] name = "execnet" version = "1.9.0" @@ -210,16 +219,35 @@ testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-co [[package]] name = "flake8" -version = "5.0.4" +version = "4.0.1" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.6" [package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.9.0,<2.10.0" -pyflakes = ">=2.5.0,<2.6.0" +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.8.0,<2.9.0" +pyflakes = ">=2.4.0,<2.5.0" + +[[package]] +name = "flakeheaven" +version = "3.2.0" +description = "FlakeHeaven is a [Flake8](https://gitlab.com/pycqa/flake8) wrapper to make it cool." +category = "dev" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +colorama = "*" +entrypoints = "*" +flake8 = ">=4.0.1,<5.0.0" +pygments = "*" +toml = "*" +urllib3 = "*" + +[package.extras] +docs = ["alabaster", "myst-parser (>=0.18.0,<0.19.0)", "pygments-github-lexers", "sphinx"] [[package]] name = "ghp-import" @@ -255,7 +283,7 @@ python-versions = ">=3.5" name = "importlib-metadata" version = "4.12.0" description = "Read metadata from Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -323,7 +351,7 @@ notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test_extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] [[package]] name = "isort" @@ -335,9 +363,9 @@ python-versions = ">=3.6.1,<4.0" [package.extras] colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile-deprecated-finder = ["pipreqs", "requirementslib"] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] +requirements_deprecated_finder = ["pip-api", "pipreqs"] [[package]] name = "jedi" @@ -389,6 +417,7 @@ optional = false python-versions = ">=3.7" [package.dependencies] +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} pywin32-ctypes = {version = "<0.1.0 || >0.1.0,<0.1.1 || >0.1.1", markers = "sys_platform == \"win32\""} SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} @@ -421,6 +450,9 @@ category = "dev" optional = false python-versions = ">=3.7" +[package.dependencies] +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} + [package.extras] testing = ["coverage", "pyyaml"] @@ -445,11 +477,11 @@ traitlets = "*" [[package]] name = "mccabe" -version = "0.7.0" +version = "0.6.1" description = "McCabe checker, plugin for flake8" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = "*" [[package]] name = "mergedeep" @@ -617,7 +649,7 @@ pastel = ">=0.2.1,<0.3.0" tomli = ">=1.2.2" [package.extras] -poetry-plugin = ["poetry (>=1.0,<2.0)"] +poetry_plugin = ["poetry (>=1.0,<2.0)"] [[package]] name = "pprintpp" @@ -667,11 +699,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pycodestyle" -version = "2.9.1" +version = "2.8.0" description = "Python style guide checker" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pycparser" @@ -683,11 +715,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pyflakes" -version = "2.5.0" +version = "2.4.0" description = "passive checker of Python programs" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" @@ -708,18 +740,6 @@ python-versions = ">=3.6.8" [package.extras] diagrams = ["jinja2", "railroad-diagrams"] -[[package]] -name = "pyproject-flake8" -version = "5.0.4.post1" -description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -flake8 = "5.0.4" -tomli = {version = "*", markers = "python_version < \"3.11\""} - [[package]] name = "pytest" version = "7.1.2" @@ -873,7 +893,7 @@ urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" @@ -1019,6 +1039,14 @@ python-versions = ">=3.7" [package.extras] test = ["pre-commit", "pytest"] +[[package]] +name = "typing-extensions" +version = "4.3.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "dev" +optional = false +python-versions = ">=3.7" + [[package]] name = "tzdata" version = "2022.1" @@ -1104,7 +1132,7 @@ python-versions = ">=3.4" name = "zipp" version = "3.8.1" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -1114,8 +1142,8 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" -python-versions = ">=3.10.0, <3.13" -content-hash = "ae08b5cb29698cb3fdaab3397d46250e0f06b04a3a4dff18c3dd9ae64b582377" +python-versions = ">=3.9.0, <3.12" +content-hash = "57ed0eb87ee7fe21231b53feb5e4bfdcd154bbb91e52c38d484ab193ff582ec8" [metadata.files] ansiwrap = [ @@ -1284,6 +1312,10 @@ distlib = [ {file = "distlib-0.3.5-py2.py3-none-any.whl", hash = "sha256:b710088c59f06338ca514800ad795a132da19fda270e3ce4affc74abf955a26c"}, {file = "distlib-0.3.5.tar.gz", hash = "sha256:a7f75737c70be3b25e2bee06288cec4e4c221de18455b2dd037fe2a795cab2fe"}, ] +entrypoints = [ + {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"}, + {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"}, +] execnet = [ {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, @@ -1297,8 +1329,12 @@ filelock = [ {file = "filelock-3.7.1.tar.gz", hash = "sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04"}, ] flake8 = [ - {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, - {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, + {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, + {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, +] +flakeheaven = [ + {file = "flakeheaven-3.2.0-py3-none-any.whl", hash = "sha256:ec5a508c3db64d73128b65cb2a5a2c0a2d9f2e4b435e9fa2bcc03bf0df86da79"}, + {file = "flakeheaven-3.2.0.tar.gz", hash = "sha256:225333d7bf309079f19a2c5f02d427fc7558a0d0c065944de88041ca94f5525c"}, ] ghp-import = [ {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, @@ -1401,8 +1437,8 @@ matplotlib-inline = [ {file = "matplotlib_inline-0.1.3-py3-none-any.whl", hash = "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c"}, ] mccabe = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] mergedeep = [ {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, @@ -1484,16 +1520,16 @@ py = [ {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pycodestyle = [ - {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, - {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, + {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, + {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, ] pycparser = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] pyflakes = [ - {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, - {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, + {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, + {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, ] pygments = [ {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"}, @@ -1503,10 +1539,6 @@ pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] -pyproject-flake8 = [ - {file = "pyproject-flake8-5.0.4.post1.tar.gz", hash = "sha256:c2dfdf1064f47efbb2e4faf1a32b0b6a6ea67dc4d1debb98d862b0cdee377941"}, - {file = "pyproject_flake8-5.0.4.post1-py2.py3-none-any.whl", hash = "sha256:457e52dde1b7a1f84b5230c70d61afa58ced64a44b81a609f19e972319fa68ed"}, -] pytest = [ {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, @@ -1668,6 +1700,10 @@ traitlets = [ {file = "traitlets-5.3.0-py3-none-any.whl", hash = "sha256:65fa18961659635933100db8ca120ef6220555286949774b9cfc106f941d1c7a"}, {file = "traitlets-5.3.0.tar.gz", hash = "sha256:0bb9f1f9f017aa8ec187d8b1b2a7a6626a2a1d877116baba52a129bfa124f8e2"}, ] +typing-extensions = [ + {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, + {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, +] tzdata = [ {file = "tzdata-2022.1-py2.py3-none-any.whl", hash = "sha256:238e70234214138ed7b4e8a0fab0e5e13872edab3be586ab8198c407620e2ab9"}, {file = "tzdata-2022.1.tar.gz", hash = "sha256:8b536a8ec63dc0751342b3984193a3118f8fca2afe25752bb9b7fffd398552d3"}, diff --git a/pyproject.toml b/pyproject.toml index 7a8b8b10..be70a1e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "jrnl" -version = "v3.2" +version = "v3.3" description = "Collect your thoughts and notes without leaving the command line." authors = [ "jrnl contributors ", @@ -44,11 +44,11 @@ tzlocal = ">=4.0" # https://github.com/regebro/tzlocal/blob/master/CHANGES.txt [tool.poetry.dev-dependencies] black = { version = ">=21.5b2", allow-prereleases = true } +flakeheaven = ">=3.0" ipdb = "*" isort = ">=5.10" mkdocs = ">=1.0,<1.3" poethepoet = "*" -pyproject-flake8 = "*" pytest = ">=6.2" pytest-bdd = ">=4.0.1,<6.0" pytest-clarity = "*" @@ -70,8 +70,9 @@ format-check = [ {cmd = "black --check --diff ."}, ] style-check = [ - {cmd = "pflake8 --version"}, - {cmd = "pflake8 jrnl tests tasks.py"}, + {cmd = "flakeheaven --version"}, + {cmd = "flakeheaven plugins"}, + {cmd = "flakeheaven lint"}, ] sort-run = [ {cmd = "isort ."}, @@ -150,9 +151,25 @@ filterwarnings = [ "ignore:[WinError 5].*" ] -[tool.flake8] -# ignore formatting warnings and errors because we use Black to autoformat -extend-ignore = "E101,E111,E114,E115,E116,E117,E12,E13,E2,E3,E401,E5,E70,W1,W2,W3,W5" +[tool.flakeheaven] +max_line_length = 88 +exclude = [".git", ".tox", ".venv", "node_modules"] + +[tool.flakeheaven.plugins] +"py*" = ["+*"] +pycodestyle = [ + "-E101", + "-E111", "-E114", "-E115", "-E116", "-E117", + "-E12*", + "-E13*", + "-E2*", + "-E3*", + "-E401", + "-E5*", + "-E70", + "-W1*", "-W2*", "-W3*", "-W5*", +] + [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/bdd/features/config_file.feature b/tests/bdd/features/config_file.feature index 6c24f1e5..3369e666 100644 --- a/tests/bdd/features/config_file.feature +++ b/tests/bdd/features/config_file.feature @@ -64,10 +64,10 @@ Feature: Multiple journals Then the output should contain "sell my junk on ebay and make lots of money" Scenario: Don't crash if no default journal is specified using an alternate config - Given the config "bug343.yaml" exists + Given the config "no_default_journal.yaml" exists And we use the config "basic_onefile.yaml" - When we run "jrnl --cf bug343.yaml a long day in the office" - Then the output should contain "No default journal configured" + When we run "jrnl --cf no_default_journal.yaml a long day in the office" + Then the output should contain "No 'default' journal configured" Scenario: Don't crash if no file exists for a configured encrypted journal using an alternate config Given the config "multiple.yaml" exists diff --git a/tests/bdd/features/format.feature b/tests/bdd/features/format.feature index 2cc7d9a1..54715495 100644 --- a/tests/bdd/features/format.feature +++ b/tests/bdd/features/format.feature @@ -612,3 +612,20 @@ Feature: Custom formats config_path: .+basic_onefile\.yaml journals: default: features/journals/basic_onefile\.journal + + Scenario: Export journal list to formats with no default journal + Given we use the config "no_default_journal.yaml" + When we run "jrnl --list" + Then the output should match + Journals defined in config \(.+no_default_journal\.yaml\) + \* simple -> features/journals/simple\.journal + \* work -> features/journals/work\.journal + When we run "jrnl --list --format json" + Then the output should match + {"config_path": ".+no_default_journal\.yaml", "journals": {"simple": "features/journals/simple\.journal", "work": "features/journals/work\.journal"}} + When we run "jrnl --list --format yaml" + Then the output should match + config_path: .+no_default_journal\.yaml + journals: + simple: features/journals/simple\.journal + work: features/journals/work\.journal diff --git a/tests/bdd/features/multiple_journals.feature b/tests/bdd/features/multiple_journals.feature index 3c2c7b73..ee90b8a9 100644 --- a/tests/bdd/features/multiple_journals.feature +++ b/tests/bdd/features/multiple_journals.feature @@ -80,9 +80,9 @@ Feature: Multiple journals 2012-07-23 09:00 sell my junk on ebay and make lots of money Scenario: Don't crash if no default journal is specified - Given we use the config "bug343.yaml" + Given we use the config "no_default_journal.yaml" When we run "jrnl a long day in the office" - Then the output should contain "No default journal configured" + Then the output should contain "No 'default' journal configured" Scenario: Don't crash if no file exists for a configured encrypted journal Given we use the config "multiple.yaml" diff --git a/tests/data/configs/bug343.yaml b/tests/data/configs/no_default_journal.yaml similarity index 100% rename from tests/data/configs/bug343.yaml rename to tests/data/configs/no_default_journal.yaml diff --git a/tests/lib/then_steps.py b/tests/lib/then_steps.py index cb7e9766..61916262 100644 --- a/tests/lib/then_steps.py +++ b/tests/lib/then_steps.py @@ -118,7 +118,7 @@ def output_should_be_columns_wide(cli_run, width): ) ) def default_journal_location(journal_file, journal_dir, config_on_disk, temp_dir): - default_journal_path = config_on_disk["journals"]["default"] + default_journal_path = config_on_disk["journals"]["default"]["journal"] expected_journal_path = ( os.path.join(temp_dir.name, journal_file) if journal_dir == "." diff --git a/tests/unit/test_export.py b/tests/unit/test_export.py index 27e60d80..1fd8663e 100644 --- a/tests/unit/test_export.py +++ b/tests/unit/test_export.py @@ -1,10 +1,16 @@ # Copyright © 2012-2022 jrnl contributors # License: https://www.gnu.org/licenses/gpl-3.0.html +from unittest import mock + import pytest from jrnl.exception import JrnlException +from jrnl.messages import Message +from jrnl.messages import MsgStyle +from jrnl.messages import MsgText from jrnl.plugins.fancy_exporter import check_provided_linewrap_viability +from jrnl.plugins.yaml_exporter import YAMLExporter @pytest.fixture() @@ -28,3 +34,15 @@ class TestFancy: with pytest.raises(JrnlException): check_provided_linewrap_viability(total_linewrap, [content], journal) + + +class TestYaml: + @mock.patch("jrnl.plugins.yaml_exporter.YAMLExporter.export_journal") + @mock.patch("builtins.open") + def test_export_to_nonexisting_folder(self, mock_open, mock_export_journal): + mock_export_journal.side_effect = JrnlException( + Message(MsgText.YamlMustBeDirectory, MsgStyle.ERROR) + ) + with pytest.raises(JrnlException): + YAMLExporter.write_file("journal", "non-existing-path") + mock_open.assert_not_called()