Move import to be standalone command to reduce clutter in cli.py

This commit is contained in:
Jonathan Wren 2020-07-03 14:29:00 -07:00
parent ce07fedc06
commit a54ed90259
9 changed files with 113 additions and 84 deletions

View file

@ -136,6 +136,40 @@ Feature: Basic reading and writing to a journal
Then the output should contain "jrnl"
And the output should contain "Python"
Scenario: Version warning appears for versions below 3.7
When we run "jrnl --diagnostic"
Then the Python version warning should appear if our version is below 3.7
Scenario: --import allows new entry to journal
Given we use the config "basic.yaml"
When we run "jrnl --import" and pipe "[2020-07-05 15:00] Observe and import."
And we run "jrnl -1"
Then the journal should contain "[2020-07-05 15:00] Observe and import."
And the output should contain "Observe and import"
Scenario: --import allows new large entry to journal
Given we use the config "basic.yaml"
When we run "jrnl --import" and pipe
"""
[2020-07-05 15:00] Observe and import.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada quis
est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque augue
et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu consequat.
Aenean ante ex, elementum ut interdum et, mattis eget lacus. In commodo nulla nec
tellus placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at
dolor dui end of entry.
"""
And we run "jrnl -1"
Then the journal should contain "[2020-07-05 15:00] Observe and import."
And the output should contain "Observe and import"
And the output should contain "Lorem ipsum"
And the output should contain "end of entry."
Scenario: --import allows import of multiple entries to journal
Given we use the config "basic.yaml"
When we run "jrnl --import" and pipe
"""
[2020-07-05 15:00] Observe and import.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
[2020-07-05 15:01] Twice as nice.
Sed dignissim sed nisl eu consequat.
"""
Then the journal should contain "[2020-07-05 15:00] Observe and import."
Then the journal should contain "[2020-07-05 15:01] Twice as nice."

View file

@ -210,8 +210,12 @@ def run_with_input(context, command, inputs=""):
@when('we run "{command}"')
@when('we run "{command}" and pipe')
@when('we run "{command}" and pipe "{text}"')
@when('we run "{command}" with cache directory "{cache_dir}"')
def run(context, command, cache_dir=None):
def run(context, command, text="", cache_dir=None):
text = text or context.text or ""
if cache_dir is not None:
cache_dir = os.path.join("features", "cache", cache_dir)
command = command.format(cache_dir=cache_dir)
@ -224,7 +228,7 @@ def run(context, command, cache_dir=None):
try:
with patch("sys.argv", args), patch(
"subprocess.call", side_effect=_mock_editor
):
), patch("sys.stdin.read", side_effect=lambda: text):
cli.run(args[1:])
context.exit_status = 0
except SystemExit as e:

View file

@ -371,7 +371,7 @@ class LegacyJournal(Journal):
return entries
def open_journal(name, config, legacy=False):
def open_journal(journal_name, config, legacy=False):
"""
Creates a normal, encrypted or DayOne journal based on the passed config.
If legacy is True, it will open Journals with legacy classes build for
@ -394,11 +394,18 @@ def open_journal(name, config, legacy=False):
if not config["encrypt"]:
if legacy:
return LegacyJournal(name, **config).open()
return PlainJournal(name, **config).open()
else:
from . import EncryptedJournal
return LegacyJournal(journal_name, **config).open()
return PlainJournal(journal_name, **config).open()
from . import EncryptedJournal
try:
if legacy:
return EncryptedJournal.LegacyEncryptedJournal(name, **config).open()
return EncryptedJournal.EncryptedJournal(name, **config).open()
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)

View file

@ -25,10 +25,10 @@ import platform
import sys
from . import install, plugins, util
from .parsing import parse_args_before_config
from .parsing import parse_args_after_config
from .parsing import parse_args
from .Journal import PlainJournal, open_journal
from .util import WARNING_COLOR, ERROR_COLOR, RESET_COLOR, UserAbort
from .util import get_journal_name
log = logging.getLogger(__name__)
logging.getLogger("keyring.backend").setLevel(logging.ERROR)
@ -38,12 +38,7 @@ def guess_mode(args, config):
"""Guesses the mode (compose, read or export) from the given arguments"""
compose = True
export = False
import_ = False
if args.import_ is not False:
compose = False
export = False
import_ = True
elif (
if (
args.decrypt is not False
or args.encrypt is not False
or args.export is not False
@ -70,7 +65,7 @@ def guess_mode(args, config):
# No date and only tags?
compose = False
return compose, export, import_
return compose, export
def encrypt(journal, filename=None):
@ -139,7 +134,7 @@ Python 3.7 (or higher) soon.
if manual_args is None:
manual_args = sys.argv[1:]
args = parse_args_before_config(manual_args)
args = parse_args(manual_args)
configure_logger(args.debug)
# Run command if possible before config is available
@ -150,38 +145,24 @@ Python 3.7 (or higher) soon.
# Load the config
try:
config = install.load_or_install_jrnl()
original_config = config.copy()
args = get_journal_name(args, config)
config = util.scope_config(config, args.journal_name)
except UserAbort as err:
print(f"\n{err}", file=sys.stderr)
sys.exit(1)
# Run command now that config is available
# Run post-config command now that config is ready
if callable(args.postconfig_cmd):
args.postconfig_cmd(config=config, args=args)
args.postconfig_cmd(args=args, config=config)
sys.exit(0)
args = parse_args_after_config(args, config)
# --- All the standalone commands are now done --- #
log.debug('Using configuration "%s"', config)
original_config = config.copy()
# Get the journal we're going to be working with
journal = open_journal(args.journal_name, config)
config = util.scope_config(config, args.journal_name)
log.debug('Using journal "%s"', args.journal_name)
mode_compose, mode_export, mode_import = guess_mode(args, config)
# How to quit writing?
if "win32" in sys.platform:
_exit_multiline_code = "on a blank line, press Ctrl+Z and then Enter"
else:
_exit_multiline_code = "press Ctrl+D"
# This is where we finally open the journal!
try:
journal = open_journal(args.journal_name, config)
except KeyboardInterrupt:
print("[Interrupted while opening journal]", file=sys.stderr)
sys.exit(1)
mode_compose, mode_export = guess_mode(args, config)
if mode_compose and not args.text:
if not sys.stdin.isatty():
@ -201,25 +182,24 @@ Python 3.7 (or higher) soon.
raw = util.get_text_from_editor(config, template)
else:
try:
_how_to_quit = (
"Ctrl+z and then Enter" if "win32" in sys.platform else "Ctrl+d"
)
print(
"[Compose Entry; " + _exit_multiline_code + " to finish writing]\n",
f"[Writing Entry; on a blank line, press {_how_to_quit} to finish writing]\n",
file=sys.stderr,
)
raw = sys.stdin.read()
except KeyboardInterrupt:
print("[Entry NOT saved to journal.]", file=sys.stderr)
print("[Entry NOT saved to journal]", file=sys.stderr)
sys.exit(0)
if raw:
args.text = [raw]
else:
sys.exit()
# Import mode
if mode_import:
plugins.get_importer(args.import_).import_(journal, args.input)
# Writing mode
elif mode_compose:
if mode_compose:
raw = " ".join(args.text).strip()
log.debug('Appending raw line "%s" to journal "%s"', raw, args.journal_name)
journal.new_entry(raw)
@ -242,7 +222,7 @@ Python 3.7 (or higher) soon.
journal.limit(args.limit)
# Reading mode
if not mode_compose and not mode_export and not mode_import:
if not mode_compose and not mode_export:
print(journal.pprint())
# Various export modes

View file

@ -21,3 +21,14 @@ def postconfig_list(config, **kwargs):
from .util import list_journals
print(list_journals(config))
def postconfig_import(args, config, **kwargs):
from .plugins import get_importer
from .Journal import open_journal
# Requires opening the journal
journal = open_journal(args.journal_name, config)
format = args.export if args.export else "jrnl"
get_importer(format).import_(journal, args.input)

View file

@ -117,14 +117,15 @@ def load_or_install_jrnl():
upgrade_config(config)
verify_config(config)
return config
else:
log.debug("Configuration file not found, installing jrnl...")
try:
config = install()
except KeyboardInterrupt:
raise UserAbort("Installation aborted")
return config
log.debug('Using configuration "%s"', config)
return config
def install():

View file

@ -8,8 +8,8 @@ from .plugins import EXPORT_FORMATS
from .commands import preconfig_version
from .commands import preconfig_diagnostic
from .commands import postconfig_list
from .commands import postconfig_import
from .util import deprecated_cmd
from .util import get_journal_name
class WrappingFormatter(argparse.RawDescriptionHelpFormatter):
@ -18,7 +18,7 @@ class WrappingFormatter(argparse.RawDescriptionHelpFormatter):
return textwrap.wrap(text, width=56)
def parse_args_before_config(args=[]):
def parse_args(args=[]):
"""
Argument parsing that is doable before the config is available.
Everything else goes into "text" for later parsing.
@ -27,7 +27,12 @@ def parse_args_before_config(args=[]):
formatter_class=WrappingFormatter,
add_help=False,
description="The command-line note-taking and journaling app.",
epilog="",
epilog=textwrap.dedent(
"""
Thank you to all of our contributors! Come see the whole list of code and
financial contributors at https://github.com/jrnl-org/jrnl. And special
thanks to Bad Lip Reading for the Yoda joke in the Writing section above."""
),
)
optional = parser.add_argument_group("Optional Arguments")
@ -108,13 +113,11 @@ def parse_args_before_config(args=[]):
)
standalone.add_argument(
"--import",
action="store_const",
metavar="TYPE",
dest="import_",
choices=IMPORT_FORMATS,
dest="postconfig_cmd",
const=postconfig_import,
help=f"Import entries into your journal. TYPE can be: {util.oxford_list(IMPORT_FORMATS)} (default: jrnl)",
default=False,
const="jrnl",
nargs="?",
)
standalone.add_argument(
"-i",
@ -132,17 +135,17 @@ def parse_args_before_config(args=[]):
The date and the following colon ("yesterday:") are optional. If you leave
them out, "now" will be used:
jrnl Then I rolled the log over, and underneath was a tiny little stick.
jrnl Then I rolled the log over.
Also, you can mark extra special entries ("star" them) with an asterisk:
jrnl *That log had a child!
jrnl *And underneath was a tiny little stick.
Please note that asterisks might be a special character in your shell, so you
might have to escape them. When in doubt about escaping, put single quotes
around your entire entry:
might have to escape them. When in doubt about escaping, put quotes around
your entire entry:
jrnl 'saturday at 8pm: *Always pass on what you have learned. -Yoda'"""
jrnl "saturday at 2am: *Then I was like 'That log had a child!'" """
composing = parser.add_argument_group(
"Writing", textwrap.dedent(compose_msg).strip()
@ -270,11 +273,3 @@ def parse_args_before_config(args=[]):
# return parser.parse_args(args)
return parser.parse_intermixed_args(args)
def parse_args_after_config(args, config):
# print(str(args)) # @todo take this out
args = get_journal_name(args, config)
return args

View file

@ -150,7 +150,6 @@ def scope_config(config, journal_name):
else:
# But also just give them a string to point to the journal file
config["journal"] = journal_conf
config.pop("journals")
return config
@ -335,4 +334,5 @@ def get_journal_name(args, config):
print(list_journals(config), file=sys.stderr)
sys.exit(1)
log.debug("Using journal name: %s", args.journal_name)
return args

View file

@ -1,4 +1,4 @@
from jrnl.cli import parse_args_before_config
from jrnl.cli import parse_args
import pytest
import shlex
@ -6,7 +6,7 @@ import shlex
def cli_as_dict(str):
cli = shlex.split(str)
args = parse_args_before_config(cli)
args = parse_args(cli)
return vars(args)
@ -21,7 +21,6 @@ def expected_args(**kwargs):
"end_date": None,
"excluded": [],
"export": False,
"import_": False,
"input": False,
"limit": None,
"on_date": None,
@ -106,11 +105,9 @@ def test_export_alone():
def test_import_alone():
assert cli_as_dict("--import jrnl") == expected_args(import_="jrnl")
from jrnl.commands import postconfig_import
def test_import_defaults_to_jrnl():
assert cli_as_dict("--import") == expected_args(import_="jrnl")
assert cli_as_dict("--import") == expected_args(postconfig_cmd=postconfig_import)
def test_input_flag_alone():