Merge branch 'develop' of https://github.com/Briscoooe/jrnl into develop

This commit is contained in:
Briscoooe 2023-01-16 12:12:37 +00:00
commit 02f8246b49
29 changed files with 131 additions and 112 deletions

View file

@ -7,6 +7,8 @@
**Implemented enhancements:** **Implemented enhancements:**
- Don't import cryptography package if not needed [\#1521](https://github.com/jrnl-org/jrnl/issues/1521) - Don't import cryptography package if not needed [\#1521](https://github.com/jrnl-org/jrnl/issues/1521)
- Refactor flow for easier access to some files \(avoid things like `jrnl.Journal.Journal` and `jrnl.jrnl` co-existing\) [\#1662](https://github.com/jrnl-org/jrnl/pull/1662) ([wren](https://github.com/wren))
- Add more type hints [\#1642](https://github.com/jrnl-org/jrnl/pull/1642) ([outa](https://github.com/outa))
- Add `rich` handler to debug logging [\#1627](https://github.com/jrnl-org/jrnl/pull/1627) ([wren](https://github.com/wren)) - Add `rich` handler to debug logging [\#1627](https://github.com/jrnl-org/jrnl/pull/1627) ([wren](https://github.com/wren))
- Rework Encryption to enable future support of other encryption methods [\#1602](https://github.com/jrnl-org/jrnl/pull/1602) ([wren](https://github.com/wren)) - Rework Encryption to enable future support of other encryption methods [\#1602](https://github.com/jrnl-org/jrnl/pull/1602) ([wren](https://github.com/wren))
@ -30,6 +32,7 @@
**Documentation:** **Documentation:**
- Documentation Change [\#1651](https://github.com/jrnl-org/jrnl/issues/1651) - Documentation Change [\#1651](https://github.com/jrnl-org/jrnl/issues/1651)
- Update docs to include time and title in arguments with `--edit` [\#1657](https://github.com/jrnl-org/jrnl/pull/1657) ([pconrad-fb](https://github.com/pconrad-fb))
- Fix markup in "Advanced Usage" doc [\#1655](https://github.com/jrnl-org/jrnl/pull/1655) ([multani](https://github.com/multani)) - Fix markup in "Advanced Usage" doc [\#1655](https://github.com/jrnl-org/jrnl/pull/1655) ([multani](https://github.com/multani))
- Remove Windows 7 known issue since Windows 7 is no longer supported [\#1636](https://github.com/jrnl-org/jrnl/pull/1636) ([micahellison](https://github.com/micahellison)) - Remove Windows 7 known issue since Windows 7 is no longer supported [\#1636](https://github.com/jrnl-org/jrnl/pull/1636) ([micahellison](https://github.com/micahellison))

View file

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

View file

@ -11,7 +11,7 @@ import colorama
from jrnl.os_compat import on_windows from jrnl.os_compat import on_windows
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
if on_windows(): if on_windows():
colorama.init() colorama.init()

View file

@ -28,7 +28,7 @@ from jrnl.messages import MsgText
from jrnl.output import print_msg from jrnl.output import print_msg
def preconfig_diagnostic(_): def preconfig_diagnostic(_) -> None:
from jrnl import __title__ from jrnl import __title__
from jrnl import __version__ from jrnl import __version__
@ -39,7 +39,7 @@ def preconfig_diagnostic(_):
) )
def preconfig_version(_): def preconfig_version(_) -> None:
import textwrap import textwrap
from jrnl import __title__ from jrnl import __title__
@ -69,7 +69,7 @@ def postconfig_list(args: argparse.Namespace, config: dict, **_) -> int:
@cmd_requires_valid_journal_name @cmd_requires_valid_journal_name
def postconfig_import(args: argparse.Namespace, config: dict, **_) -> int: def postconfig_import(args: argparse.Namespace, config: dict, **_) -> int:
from jrnl.Journal import open_journal from jrnl.journals import open_journal
from jrnl.plugins import get_importer from jrnl.plugins import get_importer
# Requires opening the journal # Requires opening the journal
@ -90,7 +90,7 @@ def postconfig_encrypt(
""" """
from jrnl.config import update_config from jrnl.config import update_config
from jrnl.install import save_config from jrnl.install import save_config
from jrnl.Journal import open_journal from jrnl.journals import open_journal
# Open the journal # Open the journal
journal = open_journal(args.journal_name, config) journal = open_journal(args.journal_name, config)
@ -145,7 +145,7 @@ def postconfig_decrypt(
"""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 jrnl.config import update_config from jrnl.config import update_config
from jrnl.install import save_config from jrnl.install import save_config
from jrnl.Journal import open_journal from jrnl.journals import open_journal
journal = open_journal(args.journal_name, config) journal = open_journal(args.journal_name, config)

View file

@ -15,8 +15,8 @@ from jrnl.config import scope_config
from jrnl.editor import get_text_from_editor from jrnl.editor import get_text_from_editor
from jrnl.editor import get_text_from_stdin from jrnl.editor import get_text_from_stdin
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.Journal import Journal from jrnl.journals import Journal
from jrnl.Journal import open_journal from jrnl.journals import open_journal
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText from jrnl.messages import MsgText
@ -28,7 +28,7 @@ from jrnl.path import expand_path
if TYPE_CHECKING: if TYPE_CHECKING:
from argparse import Namespace from argparse import Namespace
from jrnl.Entry import Entry from jrnl.journals import Entry
def run(args: "Namespace"): def run(args: "Namespace"):

View file

@ -4,6 +4,7 @@
from enum import Enum from enum import Enum
from importlib import import_module from importlib import import_module
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Type
if TYPE_CHECKING: if TYPE_CHECKING:
from .BaseEncryption import BaseEncryption from .BaseEncryption import BaseEncryption
@ -18,7 +19,7 @@ class EncryptionMethods(str, Enum):
JRNLV2 = "Jrnlv2Encryption" JRNLV2 = "Jrnlv2Encryption"
def determine_encryption_method(config: str | bool) -> "BaseEncryption": def determine_encryption_method(config: str | bool) -> Type["BaseEncryption"]:
ENCRYPTION_METHODS = { ENCRYPTION_METHODS = {
True: EncryptionMethods.JRNLV2, # the default True: EncryptionMethods.JRNLV2, # the default
False: EncryptionMethods.NONE, False: EncryptionMethods.NONE,

View file

@ -42,7 +42,7 @@ def upgrade_config(config_data: dict, alt_config_path: str | None = None) -> Non
for key in missing_keys: for key in missing_keys:
config_data[key] = default_config[key] config_data[key] = default_config[key]
different_version = (config_data["version"] != __version__) different_version = config_data["version"] != __version__
if different_version: if different_version:
config_data["version"] = __version__ config_data["version"] = __version__

View file

@ -17,13 +17,14 @@ from xml.parsers.expat import ExpatError
import tzlocal import tzlocal
from jrnl import Entry
from jrnl import Journal
from jrnl import __title__ from jrnl import __title__
from jrnl import __version__ from jrnl import __version__
from .Entry import Entry
from .Journal import Journal
class DayOne(Journal.Journal):
class DayOne(Journal):
"""A special Journal handling DayOne files""" """A special Journal handling DayOne files"""
# InvalidFileException was added to plistlib in Python3.4 # InvalidFileException was added to plistlib in Python3.4
@ -63,7 +64,7 @@ class DayOne(Journal.Journal):
if timezone.key != "UTC": if timezone.key != "UTC":
date = date.replace(fold=1) + timezone.utcoffset(date) date = date.replace(fold=1) + timezone.utcoffset(date)
entry = Entry.Entry( entry = Entry(
self, self,
date, date,
text=dict_entry["Entry Text"], text=dict_entry["Entry Text"],
@ -74,7 +75,8 @@ class DayOne(Journal.Journal):
self.config["tagsymbols"][0] + tag.lower() self.config["tagsymbols"][0] + tag.lower()
for tag in dict_entry.get("Tags", []) for tag in dict_entry.get("Tags", [])
] ]
if entry._tags: entry._tags.sort() if entry._tags:
entry._tags.sort()
"""Extended DayOne attributes""" """Extended DayOne attributes"""
# just ignore it if the keys don't exist # just ignore it if the keys don't exist
@ -196,7 +198,8 @@ class DayOne(Journal.Journal):
for entry in entries_from_editor: for entry in entries_from_editor:
entry = self._get_and_remove_uuid_from_entry(entry) entry = self._get_and_remove_uuid_from_entry(entry)
if entry._tags: entry._tags.sort() if entry._tags:
entry._tags.sort()
# Remove deleted entries # Remove deleted entries
edited_uuids = [e.uuid for e in entries_from_editor] edited_uuids = [e.uuid for e in entries_from_editor]
@ -207,7 +210,9 @@ class DayOne(Journal.Journal):
for old_entry in self.entries: for old_entry in self.entries:
if entry.uuid == old_entry.uuid: if entry.uuid == old_entry.uuid:
if old_entry._tags: if old_entry._tags:
tags_not_in_body = [tag for tag in old_entry._tags if(tag not in entry._body)] tags_not_in_body = [
tag for tag in old_entry._tags if (tag not in entry._body)
]
if tags_not_in_body: if tags_not_in_body:
entry._tags.extend(tags_not_in_body.sort()) entry._tags.extend(tags_not_in_body.sort())
self._update_old_entry(old_entry, entry) self._update_old_entry(old_entry, entry)

View file

@ -9,8 +9,8 @@ from typing import TYPE_CHECKING
import ansiwrap import ansiwrap
from .color import colorize from jrnl.color import colorize
from .color import highlight_tags_with_background_color from jrnl.color import highlight_tags_with_background_color
if TYPE_CHECKING: if TYPE_CHECKING:
from .Journal import Journal from .Journal import Journal
@ -48,33 +48,33 @@ class Entry:
self._tags = list(self._parse_tags()) self._tags = list(self._parse_tags())
@property @property
def title(self): def title(self) -> str:
if self._title is None: if self._title is None:
self._parse_text() self._parse_text()
return self._title return self._title
@title.setter @title.setter
def title(self, x): def title(self, x: str):
self._title = x self._title = x
@property @property
def body(self): def body(self) -> str:
if self._body is None: if self._body is None:
self._parse_text() self._parse_text()
return self._body return self._body
@body.setter @body.setter
def body(self, x): def body(self, x: str):
self._body = x self._body = x
@property @property
def tags(self): def tags(self) -> list[str]:
if self._tags is None: if self._tags is None:
self._parse_text() self._parse_text()
return self._tags return self._tags
@tags.setter @tags.setter
def tags(self, x): def tags(self, x: list[str]):
self._tags = x self._tags = x
@staticmethod @staticmethod
@ -218,7 +218,7 @@ class Entry:
return False return False
return True return True
def __ne__(self, other): def __ne__(self, other: "Entry"):
return not self.__eq__(other) return not self.__eq__(other)

View file

@ -6,11 +6,12 @@ import fnmatch
import os import os
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from jrnl import Journal
from jrnl import time from jrnl import time
from .Journal import Journal
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
def get_files(journal_config: str) -> list[str]: def get_files(journal_config: str) -> list[str]:
@ -22,7 +23,7 @@ def get_files(journal_config: str) -> list[str]:
return filenames return filenames
class Folder(Journal.Journal): class Folder(Journal):
"""A Journal handling multiple files in a folder""" """A Journal handling multiple files in a folder"""
def __init__(self, name: str = "default", **kwargs): def __init__(self, name: str = "default", **kwargs):

View file

@ -6,7 +6,6 @@ import logging
import os import os
import re import re
from jrnl import Entry
from jrnl import time from jrnl import time
from jrnl.config import validate_journal_name from jrnl.config import validate_journal_name
from jrnl.encryption import determine_encryption_method from jrnl.encryption import determine_encryption_method
@ -17,6 +16,8 @@ from jrnl.output import print_msg
from jrnl.path import expand_path from jrnl.path import expand_path
from jrnl.prompt import yesno from jrnl.prompt import yesno
from .Entry import Entry
class Tag: class Tag:
def __init__(self, name, count=0): def __init__(self, name, count=0):
@ -59,7 +60,7 @@ class Journal:
return (entry for entry in self.entries) return (entry for entry in self.entries)
@classmethod @classmethod
def from_journal(cls, other): def from_journal(cls, other: "Journal") -> "Journal":
"""Creates a new journal by copying configuration and entries from """Creates a new journal by copying configuration and entries from
another journal object""" another journal object"""
new_journal = cls(other.name, **other.config) new_journal = cls(other.name, **other.config)
@ -72,7 +73,7 @@ class Journal:
) )
return new_journal return new_journal
def import_(self, other_journal_txt): def import_(self, other_journal_txt: str) -> None:
imported_entries = self._parse(other_journal_txt) imported_entries = self._parse(other_journal_txt)
for entry in imported_entries: for entry in imported_entries:
entry.modified = True entry.modified = True
@ -96,7 +97,7 @@ class Journal:
return self.encryption_method.encrypt(text) return self.encryption_method.encrypt(text)
def open(self, filename=None): def open(self, filename: str | None = None) -> "Journal":
"""Opens the journal file defined in the config and parses it into a list of Entries. """Opens the journal file defined in the config and parses it into a list of Entries.
Entries have the form (date, title, body).""" Entries have the form (date, title, body)."""
filename = filename or self.config["journal"] filename = filename or self.config["journal"]
@ -130,35 +131,35 @@ class Journal:
logging.debug("opened %s with %d entries", self.__class__.__name__, len(self)) logging.debug("opened %s with %d entries", self.__class__.__name__, len(self))
return self return self
def write(self, filename=None): def write(self, filename: str | None = None) -> None:
"""Dumps the journal into the config file, overwriting it""" """Dumps the journal into the config file, overwriting it"""
filename = filename or self.config["journal"] filename = filename or self.config["journal"]
text = self._to_text() text = self._to_text()
text = self._encrypt(text) text = self._encrypt(text)
self._store(filename, text) self._store(filename, text)
def validate_parsing(self): def validate_parsing(self) -> bool:
"""Confirms that the jrnl is still parsed correctly after being dumped to text.""" """Confirms that the jrnl is still parsed correctly after being dumped to text."""
new_entries = self._parse(self._to_text()) new_entries = self._parse(self._to_text())
return all(entry == new_entries[i] for i, entry in enumerate(self.entries)) return all(entry == new_entries[i] for i, entry in enumerate(self.entries))
@staticmethod @staticmethod
def create_file(filename): def create_file(filename: str) -> None:
with open(filename, "w"): with open(filename, "w"):
pass pass
def _to_text(self): def _to_text(self) -> str:
return "\n".join([str(e) for e in self.entries]) return "\n".join([str(e) for e in self.entries])
def _load(self, filename): def _load(self, filename: str) -> bytes:
with open(filename, "rb") as f: with open(filename, "rb") as f:
return f.read() return f.read()
def _store(self, filename, text): def _store(self, filename: str, text: bytes) -> None:
with open(filename, "wb") as f: with open(filename, "wb") as f:
f.write(text) f.write(text)
def _parse(self, journal_txt): def _parse(self, journal_txt: str) -> list[Entry]:
"""Parses a journal that's stored in a string and returns a list of entries""" """Parses a journal that's stored in a string and returns a list of entries"""
# Return empty array if the journal is blank # Return empty array if the journal is blank
@ -184,11 +185,11 @@ class Journal:
if entries: if entries:
entries[-1].text = journal_txt[last_entry_pos : match.start()] entries[-1].text = journal_txt[last_entry_pos : match.start()]
last_entry_pos = match.end() last_entry_pos = match.end()
entries.append(Entry.Entry(self, date=new_date)) entries.append(Entry(self, date=new_date))
# If no entries were found, treat all the existing text as an entry made now # If no entries were found, treat all the existing text as an entry made now
if not entries: if not entries:
entries.append(Entry.Entry(self, date=time.parse("now"))) entries.append(Entry(self, date=time.parse("now")))
# Fill in the text of the last entry # Fill in the text of the last entry
entries[-1].text = journal_txt[last_entry_pos:] entries[-1].text = journal_txt[last_entry_pos:]
@ -197,7 +198,7 @@ class Journal:
entry._parse_text() entry._parse_text()
return entries return entries
def pprint(self, short=False): def pprint(self, short: bool = False) -> str:
"""Prettyprints the journal's entries""" """Prettyprints the journal's entries"""
return "\n".join([e.pprint(short=short) for e in self.entries]) return "\n".join([e.pprint(short=short) for e in self.entries])
@ -207,17 +208,17 @@ class Journal:
def __repr__(self): def __repr__(self):
return f"<Journal with {len(self.entries)} entries>" return f"<Journal with {len(self.entries)} entries>"
def sort(self): def sort(self) -> None:
"""Sorts the Journal's entries by date""" """Sorts the Journal's entries by date"""
self.entries = sorted(self.entries, key=lambda entry: entry.date) self.entries = sorted(self.entries, key=lambda entry: entry.date)
def limit(self, n=None): def limit(self, n: int | None = None) -> None:
"""Removes all but the last n entries""" """Removes all but the last n entries"""
if n: if n:
self.entries = self.entries[-n:] self.entries = self.entries[-n:]
@property @property
def tags(self): def tags(self) -> list[Tag]:
"""Returns a set of tuples (count, tag) for all tags present in the journal.""" """Returns a set of tuples (count, tag) for all tags present in the journal."""
# Astute reader: should the following line leave you as puzzled as me the first time # Astute reader: should the following line leave you as puzzled as me the first time
# I came across this construction, worry not and embrace the ensuing moment of enlightment. # I came across this construction, worry not and embrace the ensuing moment of enlightment.
@ -228,16 +229,16 @@ class Journal:
def filter( def filter(
self, self,
tags=[], tags: list = [],
month=None, month: str | int | None = None,
day=None, day: str | int | None = None,
year=None, year: str | None = None,
start_date=None, start_date: str | None = None,
end_date=None, end_date: str | None = None,
starred=False, starred: bool = False,
strict=False, strict: bool = False,
contains=None, contains: bool = None,
exclude=[], exclude: list = [],
): ):
"""Removes all entries from the journal that don't match the filter. """Removes all entries from the journal that don't match the filter.
@ -293,19 +294,19 @@ class Journal:
self.entries = result self.entries = result
def delete_entries(self, entries_to_delete): def delete_entries(self, entries_to_delete: list[Entry]) -> None:
"""Deletes specific entries from a journal.""" """Deletes specific entries from a journal."""
for entry in entries_to_delete: for entry in entries_to_delete:
self.entries.remove(entry) self.entries.remove(entry)
def change_date_entries(self, date): def change_date_entries(self, date: datetime.datetime | None) -> None:
"""Changes entry dates to given date.""" """Changes entry dates to given date."""
date = time.parse(date) date = time.parse(date)
for entry in self.entries: for entry in self.entries:
entry.date = date entry.date = date
def prompt_action_entries(self, msg: MsgText): def prompt_action_entries(self, msg: MsgText) -> list[Entry]:
"""Prompts for action for each entry in a journal, using given message. """Prompts for action for each entry in a journal, using given message.
Returns the entries the user wishes to apply the action on.""" Returns the entries the user wishes to apply the action on."""
to_act = [] to_act = []
@ -325,7 +326,7 @@ class Journal:
return to_act return to_act
def new_entry(self, raw, date=None, sort=True): def new_entry(self, raw: str, date=None, sort: bool = True) -> Entry:
"""Constructs a new entry from some raw text input. """Constructs a new entry from some raw text input.
If a date is given, it will parse and use this, otherwise scan for a date in the input first.""" If a date is given, it will parse and use this, otherwise scan for a date in the input first."""
@ -354,19 +355,19 @@ class Journal:
) )
if not date: # Still nothing? Meh, just live in the moment. if not date: # Still nothing? Meh, just live in the moment.
date = time.parse("now") date = time.parse("now")
entry = Entry.Entry(self, date, raw, starred=starred) entry = Entry(self, date, raw, starred=starred)
entry.modified = True entry.modified = True
self.entries.append(entry) self.entries.append(entry)
if sort: if sort:
self.sort() self.sort()
return entry return entry
def editable_str(self): def editable_str(self) -> str:
"""Turns the journal into a string of entries that can be edited """Turns the journal into a string of entries that can be edited
manually and later be parsed with self.parse_editable_str.""" manually and later be parsed with self.parse_editable_str."""
return "\n".join([str(e) for e in self.entries]) return "\n".join([str(e) for e in self.entries])
def parse_editable_str(self, edited): def parse_editable_str(self, edited: str) -> None:
"""Parses the output of self.editable_str and updates it's entries.""" """Parses the output of self.editable_str and updates it's entries."""
mod_entries = self._parse(edited) mod_entries = self._parse(edited)
# Match those entries that can be found in self.entries and set # Match those entries that can be found in self.entries and set
@ -382,7 +383,7 @@ class LegacyJournal(Journal):
standard. Main difference here is that in 1.x, timestamps were not cuddled standard. Main difference here is that in 1.x, timestamps were not cuddled
by square brackets. You'll not be able to save these journals anymore.""" by square brackets. You'll not be able to save these journals anymore."""
def _parse(self, journal_txt): def _parse(self, journal_txt: str) -> list[Entry]:
"""Parses a journal that's stored in a string and returns a list of entries""" """Parses a journal that's stored in a string and returns a list of entries"""
# Entries start with a line that looks like 'date title' - let's figure out how # Entries start with a line that looks like 'date title' - let's figure out how
# long the date will be by constructing one # long the date will be by constructing one
@ -410,7 +411,7 @@ class LegacyJournal(Journal):
else: else:
starred = False starred = False
current_entry = Entry.Entry( current_entry = Entry(
self, date=new_date, text=line[date_length + 1 :], starred=starred self, date=new_date, text=line[date_length + 1 :], starred=starred
) )
except ValueError: except ValueError:
@ -429,7 +430,7 @@ class LegacyJournal(Journal):
return entries return entries
def open_journal(journal_name, config, legacy=False): def open_journal(journal_name: str, config: dict, legacy: bool = False) -> Journal:
""" """
Creates a normal, encrypted or DayOne journal based on the passed config. 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 If legacy is True, it will open Journals with legacy classes build for
@ -455,21 +456,21 @@ 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 jrnl import DayOneJournal from jrnl.journals import DayOne
return DayOneJournal.DayOne(**config).open() return DayOne(**config).open()
else: else:
from jrnl import FolderJournal from jrnl.journals import Folder
return FolderJournal.Folder(journal_name, **config).open() return Folder(journal_name, **config).open()
if not config["encrypt"]: if not config["encrypt"]:
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 jrnl import FolderJournal from jrnl.journals import Folder
return FolderJournal.Folder(journal_name, **config).open() return Folder(journal_name, **config).open()
return Journal(journal_name, **config).open() return Journal(journal_name, **config).open()
if legacy: if legacy:

View file

@ -0,0 +1,5 @@
from .DayOneJournal import DayOne
from .Entry import Entry
from .FolderJournal import Folder
from .Journal import Journal
from .Journal import open_journal

View file

@ -18,7 +18,7 @@ def get_keyring_password(journal_name: str = "default") -> str | None:
return None return None
def set_keyring_password(password: str, journal_name: str = "default"): def set_keyring_password(password: str, journal_name: str = "default") -> None:
try: try:
return keyring.set_password("jrnl", journal_name, password) return keyring.set_password("jrnl", journal_name, password)
except keyring.errors.KeyringError as e: except keyring.errors.KeyringError as e:

View file

@ -7,9 +7,9 @@ import traceback
from rich.logging import RichHandler from rich.logging import RichHandler
from jrnl import controller
from jrnl.args import parse_args from jrnl.args import parse_args
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 MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText from jrnl.messages import MsgText
@ -32,7 +32,7 @@ def configure_logger(debug: bool = False) -> None:
logging.debug("Logging start") logging.debug("Logging start")
def cli(manual_args: list[str] | None = None) -> int: def run(manual_args: list[str] | None = None) -> int:
try: try:
if manual_args is None: if manual_args is None:
manual_args = sys.argv[1:] manual_args = sys.argv[1:]
@ -41,7 +41,7 @@ def cli(manual_args: list[str] | None = None) -> int:
configure_logger(args.debug) configure_logger(args.debug)
logging.debug("Parsed args:\n%s", args) logging.debug("Parsed args:\n%s", args)
status_code = run(args) status_code = controller.run(args)
except JrnlException as e: except JrnlException as e:
status_code = 1 status_code = 1

View file

@ -7,8 +7,8 @@ from typing import TYPE_CHECKING
from jrnl.plugins.text_exporter import TextExporter from jrnl.plugins.text_exporter import TextExporter
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
from jrnl.Journal import Journal from jrnl.journals import Journal
class DatesExporter(TextExporter): class DatesExporter(TextExporter):

View file

@ -13,8 +13,8 @@ from jrnl.messages import MsgText
from jrnl.plugins.text_exporter import TextExporter from jrnl.plugins.text_exporter import TextExporter
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
from jrnl.Journal import Journal from jrnl.journals import Journal
class FancyExporter(TextExporter): class FancyExporter(TextExporter):

View file

@ -11,7 +11,7 @@ from jrnl.messages import MsgText
from jrnl.output import print_msg from jrnl.output import print_msg
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Journal import Journal from jrnl.journals import Journal
class JRNLImporter: class JRNLImporter:

View file

@ -8,8 +8,8 @@ from jrnl.plugins.text_exporter import TextExporter
from jrnl.plugins.util import get_tags_count from jrnl.plugins.util import get_tags_count
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
from jrnl.Journal import Journal from jrnl.journals import Journal
class JSONExporter(TextExporter): class JSONExporter(TextExporter):

View file

@ -12,8 +12,8 @@ from jrnl.output import print_msg
from jrnl.plugins.text_exporter import TextExporter from jrnl.plugins.text_exporter import TextExporter
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
from jrnl.Journal import Journal from jrnl.journals import Journal
class MarkdownExporter(TextExporter): class MarkdownExporter(TextExporter):

View file

@ -7,8 +7,8 @@ from jrnl.plugins.text_exporter import TextExporter
from jrnl.plugins.util import get_tags_count from jrnl.plugins.util import get_tags_count
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
from jrnl.Journal import Journal from jrnl.journals import Journal
class TagExporter(TextExporter): class TagExporter(TextExporter):

View file

@ -13,8 +13,8 @@ from jrnl.messages import MsgText
from jrnl.output import print_msg from jrnl.output import print_msg
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
from jrnl.Journal import Journal from jrnl.journals import Journal
class TextExporter: class TextExporter:

View file

@ -4,7 +4,7 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Journal import Journal from jrnl.journals import Journal
def get_tags_count(journal: "Journal") -> set[tuple[int, str]]: def get_tags_count(journal: "Journal") -> set[tuple[int, str]]:

View file

@ -8,8 +8,8 @@ from jrnl.plugins.json_exporter import JSONExporter
from jrnl.plugins.util import get_tags_count from jrnl.plugins.util import get_tags_count
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
from jrnl.Journal import Journal from jrnl.journals import Journal
class XMLExporter(JSONExporter): class XMLExporter(JSONExporter):

View file

@ -13,8 +13,8 @@ from jrnl.output import print_msg
from jrnl.plugins.text_exporter import TextExporter from jrnl.plugins.text_exporter import TextExporter
if TYPE_CHECKING: if TYPE_CHECKING:
from jrnl.Entry import Entry from jrnl.journals import Entry
from jrnl.Journal import Journal from jrnl.journals import Journal
class YAMLExporter(TextExporter): class YAMLExporter(TextExporter):
@ -34,7 +34,7 @@ class YAMLExporter(TextExporter):
body = body_wrapper + entry.body body = body_wrapper + entry.body
tagsymbols = entry.journal.config["tagsymbols"] tagsymbols = entry.journal.config["tagsymbols"]
# see also Entry.Entry.rag_regex # see also Entry.rag_regex
multi_tag_regex = re.compile(rf"(?u)^\s*([{tagsymbols}][-+*#/\w]+\s*)+$") multi_tag_regex = re.compile(rf"(?u)^\s*([{tagsymbols}][-+*#/\w]+\s*)+$")
"""Increase heading levels in body text""" """Increase heading levels in body text"""

View file

@ -4,12 +4,13 @@
import logging import logging
import os import os
from jrnl import Journal
from jrnl import __version__ from jrnl import __version__
from jrnl.config import is_config_json from jrnl.config import is_config_json
from jrnl.config import load_config from jrnl.config import load_config
from jrnl.config import scope_config from jrnl.config import scope_config
from jrnl.exception import JrnlException from jrnl.exception import JrnlException
from jrnl.journals import Journal
from jrnl.journals import open_journal
from jrnl.messages import Message from jrnl.messages import Message
from jrnl.messages import MsgStyle from jrnl.messages import MsgStyle
from jrnl.messages import MsgText from jrnl.messages import MsgText
@ -129,14 +130,14 @@ def upgrade_jrnl(config_path: str) -> None:
) )
backup(path, binary=True) backup(path, binary=True)
old_journal = Journal.open_journal( old_journal = open_journal(
journal_name, scope_config(config, journal_name), legacy=True journal_name, scope_config(config, journal_name), legacy=True
) )
logging.debug(f"Clearing encryption method for '{journal_name}' journal") logging.debug(f"Clearing encryption method for '{journal_name}' journal")
# Update the encryption method # Update the encryption method
new_journal = Journal.Journal.from_journal(old_journal) new_journal = Journal.from_journal(old_journal)
new_journal.config["encrypt"] = "jrnlv2" new_journal.config["encrypt"] = "jrnlv2"
new_journal._get_encryption_method() new_journal._get_encryption_method()
# Copy over password (jrnlv1 only supported password-based encryption) # Copy over password (jrnlv1 only supported password-based encryption)
@ -156,10 +157,10 @@ def upgrade_jrnl(config_path: str) -> None:
) )
backup(path) backup(path)
old_journal = Journal.open_journal( old_journal = open_journal(
journal_name, scope_config(config, journal_name), legacy=True journal_name, scope_config(config, journal_name), legacy=True
) )
all_journals.append(Journal.Journal.from_journal(old_journal)) all_journals.append(Journal.from_journal(old_journal))
# loop through lists to validate # loop through lists to validate
failed_journals = [j for j in all_journals if not j.validate_parsing()] failed_journals = [j for j in all_journals if not j.validate_parsing()]

View file

@ -63,7 +63,7 @@ tox = "*"
xmltodict = "*" xmltodict = "*"
[tool.poetry.scripts] [tool.poetry.scripts]
jrnl = 'jrnl.cli:cli' jrnl = 'jrnl.main:run'
[tool.poe.tasks] [tool.poe.tasks]
docs-check.default_item_type = "script" docs-check.default_item_type = "script"
@ -157,6 +157,8 @@ pycodestyle = [
"flake8-*" = ["+*"] "flake8-*" = ["+*"]
flake8-black = ["-BLK901"] flake8-black = ["-BLK901"]
[tool.flakeheaven.exceptions."jrnl/journals/__init__.py"]
pyflakes = ["-F401"]
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]

View file

@ -144,7 +144,7 @@ def mock_overrides(config_in_memory):
return { return {
"overrides": lambda: patch( "overrides": lambda: patch(
"jrnl.jrnl.apply_overrides", side_effect=my_overrides "jrnl.controller.apply_overrides", side_effect=my_overrides
) )
} }

View file

@ -8,7 +8,7 @@ from pytest_bdd import when
from pytest_bdd.parsers import parse from pytest_bdd.parsers import parse
from pytest_bdd.parsers import re from pytest_bdd.parsers import re
from jrnl.cli import cli from jrnl.main import run
@when(parse('we change directory to "{directory_name}"')) @when(parse('we change directory to "{directory_name}"'))
@ -44,7 +44,7 @@ def we_run_jrnl(cli_run, capsys, keyring):
mocks[id] = stack.enter_context(factories[id]()) mocks[id] = stack.enter_context(factories[id]())
try: try:
cli_run["status"] = cli() or 0 cli_run["status"] = run() or 0
except StopIteration: except StopIteration:
# This happens when input is expected, but don't have any input left # This happens when input is expected, but don't have any input left
pass pass

View file

@ -9,7 +9,7 @@ import pytest
import jrnl import jrnl
from jrnl.args import parse_args from jrnl.args import parse_args
from jrnl.jrnl import _display_search_results from jrnl.controller import _display_search_results
@pytest.fixture @pytest.fixture
@ -19,10 +19,10 @@ def random_string():
@pytest.mark.parametrize("export_format", ["pretty", "short"]) @pytest.mark.parametrize("export_format", ["pretty", "short"])
@mock.patch("builtins.print") @mock.patch("builtins.print")
@mock.patch("jrnl.Journal.Journal.pprint") @mock.patch("jrnl.controller.Journal.pprint")
def test_display_search_results_pretty_short(mock_pprint, mock_print, export_format): def test_display_search_results_pretty_short(mock_pprint, mock_print, export_format):
mock_args = parse_args(["--format", export_format]) mock_args = parse_args(["--format", export_format])
test_journal = mock.Mock(wraps=jrnl.Journal.Journal) test_journal = mock.Mock(wraps=jrnl.journals.Journal)
_display_search_results(mock_args, test_journal) _display_search_results(mock_args, test_journal)
@ -40,7 +40,7 @@ def test_display_search_results_builtin_plugins(
test_filename = random_string test_filename = random_string
mock_args = parse_args(["--format", export_format, "--file", test_filename]) mock_args = parse_args(["--format", export_format, "--file", test_filename])
test_journal = mock.Mock(wraps=jrnl.Journal.Journal) test_journal = mock.Mock(wraps=jrnl.journals.Journal)
mock_export = mock.Mock() mock_export = mock.Mock()
mock_exporter.return_value.export = mock_export mock_exporter.return_value.export = mock_export