Skip to content

Commit

Permalink
Reformat additional messages and finish centralizing exception handli…
Browse files Browse the repository at this point in the history
…ng (#1424)

* Update and modularize exception handling

cc #1024 #1141

- Stack traces are no longer shown to users unless the --debug flag is
  being used
- Errors, warnings, and other messages contain color as needed
- Converted error messages to Enum
- Adds print_msg function to centralize output (this should replace all
  other output in other modules)

Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>

* format with black

* add message to catch-all exception block

* Unskip some tests (#1399)

* remove skip_editor test and tag

* remove useless test

* unskip blank input test

* formatting

* rename test so it doesn't overwrite other test

* unskip some dayone tests that now work

* Bump ipython from 7.28.0 to 7.31.1 (#1401)

Bumps [ipython](https://github.com/ipython/ipython) from 7.28.0 to 7.31.1.
- [Release notes](https://github.com/ipython/ipython/releases)
- [Commits](ipython/ipython@7.28.0...7.31.1)

---
updated-dependencies:
- dependency-name: ipython
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog [ci skip]

* Bump asteval from 0.9.25 to 0.9.26 (#1400)

Bumps [asteval](https://github.com/newville/asteval) from 0.9.25 to 0.9.26.
- [Release notes](https://github.com/newville/asteval/releases)
- [Commits](newville/asteval@0.9.25...0.9.26)

---
updated-dependencies:
- dependency-name: asteval
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog [ci skip]

* Bump black from 21.12b0 to 22.1.0 (#1404)

* Bump black from 21.12b0 to 22.1.0

Bumps [black](https://github.com/psf/black) from 21.12b0 to 22.1.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/commits/22.1.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* Run make format

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>

* Update changelog [ci skip]

* Add reference documentation to docs site and separate out "Tips and Tricks" and "External Editors" from "Recipes" (#1332)

* First draft of command line reference, mostly pulled from help screen

* Add first draft of config file reference, mostly pulled from advanced.md

* Clean up config file doc for readability

* Add --config-file and remove examples from CLI reference

* Add warning about time zone in timeformat

* More small changes, and adding template config keyword

* Cleaning up and re-ordering config file reference

* Clean up reference and anything else from advanced documentation that can live elsewhere and linking to config file reference wherever config file is mentioned

* Fix syntax highlighting in command line reference, clean up content a bit, include --diagnostic

* Mention version config key

* Apply minor changes suggested in PR review

* Rename "recipes" to "Tips and Tricks", pull "External Editors" out of it into its own page, and redirect old recipes link to tips-and-tricks

* Revert broken mkdocs-redirects usage from last commit

* Update changelog [ci skip]

* Add --co alias for --config-override (#1397)

* Add hash as a default tag symbol (#1398)

* Update changelog [ci skip]

* Increment version to v2.8.4-beta2

* Update changelog [ci skip]

* Increment version to v2.8.4

* Update changelog [ci skip]

* Bump pytest from 6.2.5 to 7.0.0 (#1407)

Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.5 to 7.0.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pytest@6.2.5...7.0.0)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog [ci skip]

* Drop support for Python 3.7 and 3.8 (#1412)

* Remove Python 3.7 and 3.8 from github actions workflows

* Update lockfile after running poetry update a couple times

* Update poetry lock

* Remove Python 3.7 and 3.8 from pyproject.toml and run poetry lock

* Update changelog [ci skip]

* Tidy up git ignore (#1414)

* cleaned gitignore and add comments

* removed colon for readbility

* alphabetize files in sections

Co-authored-by: nelnog <nel.nogales@gmail.com>

* fix behavior that was confusing pytest

* update test to match new message

* whitespace change

* clean up error for manually stopping the inline editor

* udpate error to use new exception handling

* move some exceptions and errors to the new exception handling

* add line breaks to keyboard interrupt so it looks more like other exceptions

* add handling for exceptions that happen earlier in the flow

* add new 'NothingToDelete' error to replace old behavior

* get rid of old exception

* add new exception handling to 'nothing saved to file' errors

* move exception for no editor configured into new handling

* move exception for no alt config to new handling

* get rid of old exception handling for encrypted journal

* Move error for too many wrong passwords into new handling

* fix merge errors

* replace sys.exit call with new exception handling

* replace sys.exit call with new exception handling

* replace sys.exit call with new exception handling

* reformat with black

* clean up old code

* clean up old code

* clean up linting issue

* update uncaught exception for new handling

* update test

* fix mangled lock file

Co-authored-by: Micah Jerome Ellison <micah.jerome.ellison@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jrnl Bot <jrnl.bot@gmail.com>
Co-authored-by: Nelson <35701520+nelnog@users.noreply.github.com>
Co-authored-by: nelnog <nel.nogales@gmail.com>
  • Loading branch information
6 people committed Mar 19, 2022
1 parent a111791 commit bc42f74
Show file tree
Hide file tree
Showing 16 changed files with 205 additions and 154 deletions.
29 changes: 15 additions & 14 deletions jrnl/EncryptedJournal.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
from .Journal import LegacyJournal
from .prompt import create_password

from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgType


def make_key(password):
password = password.encode("utf-8")
Expand Down Expand Up @@ -53,11 +58,11 @@ def decrypt_content(
password = getpass.getpass()
result = decrypt_func(password)
attempt += 1
if result is not None:
return result
else:
print("Extremely wrong password.", file=sys.stderr)
sys.exit(1)

if result is None:
raise JrnlException(Message(MsgText.PasswordMaxTriesExceeded, MsgType.ERROR))

return result


class EncryptedJournal(Journal):
Expand Down Expand Up @@ -121,15 +126,11 @@ def _store(self, filename, text):
@classmethod
def from_journal(cls, other: Journal):
new_journal = super().from_journal(other)
try:
new_journal.password = (
other.password
if hasattr(other, "password")
else create_password(other.name)
)
except KeyboardInterrupt:
print("[Interrupted while creating new journal]", file=sys.stderr)
sys.exit(1)
new_journal.password = (
other.password
if hasattr(other, "password")
else create_password(other.name)
)

return new_journal

Expand Down
13 changes: 3 additions & 10 deletions jrnl/Journal.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,6 @@ def open_journal(journal_name, config, legacy=False):

from . import EncryptedJournal

try:
if legacy:
return EncryptedJournal.LegacyEncryptedJournal(
journal_name, **config
).open()
return EncryptedJournal.EncryptedJournal(journal_name, **config).open()
except KeyboardInterrupt:
# Since encrypted journals prompt for a password, it's easy for a user to ctrl+c out
print("[Interrupted while opening journal]", file=sys.stderr)
sys.exit(1)
if legacy:
return EncryptedJournal.LegacyEncryptedJournal(journal_name, **config).open()
return EncryptedJournal.EncryptedJournal(journal_name, **config).open()
40 changes: 28 additions & 12 deletions jrnl/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import sys
import traceback

from jrnl.jrnl import run
from jrnl.args import parse_args
from .jrnl import run
from .args import parse_args
from jrnl.output import print_msg

from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgText
Expand Down Expand Up @@ -36,25 +37,40 @@ def cli(manual_args=None):
configure_logger(args.debug)
logging.debug("Parsed args: %s", args)

return run(args)
status_code = run(args)

except JrnlException as e:
status_code = 1
e.print()
return 1

except KeyboardInterrupt:
print_msg(Message(MsgText.KeyboardInterruptMsg, MsgType.WARNING))
return 1
status_code = 1
print_msg("\nKeyboardInterrupt", "\nAborted by user", msg=Message.ERROR)

except Exception as e:
# uncaught exception
status_code = 1
debug = False
try:
is_debug = args.debug # type: ignore
if args.debug: # type: ignore
debug = True
except NameError:
# error happened before args were parsed
is_debug = "--debug" in sys.argv[1:]
# This should only happen when the exception
# happened before the args were parsed
if "--debug" in sys.argv:
debug = True

if is_debug:
if debug:
print("\n")
traceback.print_tb(sys.exc_info()[2])

print_msg(Message(MsgText.UncaughtException, MsgType.ERROR, {"exception": e}))
return 1
print_msg(
Message(
MsgText.UncaughtException,
MsgType.ERROR,
{"name": type(e).__name__, "exception": e},
)
)

# This should be the only exit point
return status_code
10 changes: 7 additions & 3 deletions jrnl/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,13 @@ def get_journal_name(args, config):
args.text = args.text[1:]

if args.journal_name not in config["journals"]:
print("No default journal configured.", file=sys.stderr)
print(list_journals(config), file=sys.stderr)
sys.exit(1)
raise JrnlException(
Message(
MsgText.NoDefaultJournal,
MsgType.ERROR,
{"journals": list_journals(config)},
),
)

logging.debug("Using journal name: %s", args.journal_name)
return args
22 changes: 9 additions & 13 deletions jrnl/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
import subprocess
import sys
import tempfile
import textwrap
from pathlib import Path

from jrnl.color import ERROR_COLOR
from jrnl.color import RESET_COLOR
from jrnl.os_compat import on_windows
from jrnl.os_compat import split_args
from jrnl.output import print_msg
Expand All @@ -32,22 +29,21 @@ def get_text_from_editor(config, template=""):

try:
subprocess.call(split_args(config["editor"]) + [tmpfile])
except FileNotFoundError as e:
error_msg = f"""
{ERROR_COLOR}{str(e)}{RESET_COLOR}
Please check the 'editor' key in your config file for errors:
{repr(config['editor'])}
"""
print(textwrap.dedent(error_msg).strip(), file=sys.stderr)
exit(1)
except FileNotFoundError:
raise JrnlException(
Message(
MsgText.EditorMisconfigured,
MsgType.ERROR,
{"editor_key": config["editor"]},
)
)

with open(tmpfile, "r", encoding="utf-8") as f:
raw = f.read()
os.remove(tmpfile)

if not raw:
print("[Nothing saved to file]", file=sys.stderr)
raise JrnlException(Message(MsgText.NoTextReceived, MsgType.ERROR))

return raw

Expand Down
10 changes: 0 additions & 10 deletions jrnl/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,6 @@
from jrnl.output import print_msg


class UserAbort(Exception):
pass


class UpgradeValidationException(Exception):
"""Raised when the contents of an upgraded journal do not match the old journal"""

pass


class JrnlException(Exception):
"""Common exceptions raised by jrnl."""

Expand Down
44 changes: 16 additions & 28 deletions jrnl/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@
from .config import load_config
from .config import save_config
from .config import verify_config_colors
from .exception import UserAbort
from .prompt import yesno
from .upgrade import is_old_version

from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgType


def upgrade_config(config_data, alt_config_path=None):
"""Checks if there are keys missing in a given config dict, and if so, updates the config file accordingly.
Expand Down Expand Up @@ -47,14 +51,14 @@ def find_default_config():


def find_alt_config(alt_config):
if os.path.exists(alt_config):
return alt_config
else:
print(
"Alternate configuration file not found at path specified.", file=sys.stderr
if not os.path.exists(alt_config):
raise JrnlException(
Message(
MsgText.AltConfigNotFound, MsgType.ERROR, {"config_file": alt_config}
)
)
print("Exiting.", file=sys.stderr)
sys.exit(1)

return alt_config


def load_or_install_jrnl(alt_config_path):
Expand All @@ -72,32 +76,16 @@ def load_or_install_jrnl(alt_config_path):
config = load_config(config_path)

if is_old_version(config_path):
from . import upgrade

try:
upgrade.upgrade_jrnl(config_path)
except upgrade.UpgradeValidationException:
print("Aborting upgrade.", file=sys.stderr)
print(
"Please tell us about this problem at the following URL:",
file=sys.stderr,
)
print(
"https://github.com/jrnl-org/jrnl/issues/new?title=UpgradeValidationException",
file=sys.stderr,
)
print("Exiting.", file=sys.stderr)
sys.exit(1)
from jrnl import upgrade

upgrade.upgrade_jrnl(config_path)

upgrade_config(config, alt_config_path)
verify_config_colors(config)

else:
logging.debug("Configuration file not found, installing jrnl...")
try:
config = install()
except KeyboardInterrupt:
raise UserAbort("Installation aborted")
config = install()

logging.debug('Using configuration "%s"', config)
return config
Expand Down
59 changes: 27 additions & 32 deletions jrnl/jrnl.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@
from . import install
from . import plugins
from .Journal import open_journal
from .color import ERROR_COLOR
from .color import RESET_COLOR
from .config import get_journal_name
from .config import scope_config
from .config import get_config_path
from .editor import get_text_from_editor
from .editor import get_text_from_stdin
from .exception import UserAbort
from . import time
from .override import apply_overrides

from jrnl.exception import JrnlException
from jrnl.messages import Message
from jrnl.messages import MsgText
from jrnl.messages import MsgType


def run(args):
"""
Expand All @@ -35,18 +37,14 @@ def run(args):
return args.preconfig_cmd(args)

# Load the config, and extract journal name
try:
config = install.load_or_install_jrnl(args.config_file_path)
original_config = config.copy()
config = install.load_or_install_jrnl(args.config_file_path)
original_config = config.copy()

# Apply config overrides
config = apply_overrides(args, config)
# Apply config overrides
config = apply_overrides(args, config)

args = get_journal_name(args, config)
config = scope_config(config, args.journal_name)
except UserAbort as err:
print(f"\n{err}", file=sys.stderr)
sys.exit(1)
args = get_journal_name(args, config)
config = scope_config(config, args.journal_name)

# Run post-config command now that config is ready
if callable(args.postconfig_cmd):
Expand Down Expand Up @@ -138,7 +136,9 @@ def write_mode(args, config, journal, **kwargs):

if not raw:
logging.error("Write mode: couldn't get raw text")
sys.exit()
raise JrnlException(
Message(MsgText.JrnlExceptionMessage.NoTextReceived, MsgType.ERROR)
)

logging.debug(
'Write mode: appending raw text to journal "%s": %s', args.journal_name, raw
Expand Down Expand Up @@ -202,11 +202,13 @@ def _get_editor_template(config, **kwargs):
logging.debug("Write mode: template loaded: %s", template)
except OSError:
logging.error("Write mode: template not loaded")
print(
f"[Could not read template at '{config['template']}']",
file=sys.stderr,
raise JrnlException(
Message(
MsgText.CantReadTemplate,
MsgType.ERROR,
{"template": config["template"]},
)
)
sys.exit(1)

return template

Expand Down Expand Up @@ -243,16 +245,13 @@ def _edit_search_results(config, journal, old_entries, **kwargs):
3. Write modifications to journal
"""
if not config["editor"]:
print(
f"""
[{ERROR_COLOR}ERROR{RESET_COLOR}: There is no editor configured.]
Please specify an editor in config file ({get_config_path()})
to use the --edit option.
""",
file=sys.stderr,
raise JrnlException(
Message(
MsgText.EditorNotConfigured,
MsgType.ERROR,
{"config_file": get_config_path()},
)
)
sys.exit(1)

# separate entries we are not editing
other_entries = [e for e in old_entries if e not in journal.entries]
Expand Down Expand Up @@ -310,11 +309,7 @@ def _pluralize_entry(num):

def _delete_search_results(journal, old_entries, **kwargs):
if not journal.entries:
print(
"[No entries deleted, because the search returned no results.]",
file=sys.stderr,
)
sys.exit(1)
raise JrnlException(Message(MsgText.NothingToDelete, MsgType.ERROR))

entries_to_delete = journal.prompt_delete_entries()

Expand Down

0 comments on commit bc42f74

Please sign in to comment.