mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-05-10 08:38:32 +02:00
Refactor --template code (#1711)
* Move path concerns to path.py and template concerns to editor.py -- BDD tests are failing * Move path-related constants from config.py to path.py * Mock get_templates_path in its new calling file * Mediate template arg vs. config in controller then read template text in editor and unify those two use cases. Some tests still failing * Fix test whose message had changed * poe format * Refactor for easier unit testing and add unit tests * Use path strings instead of Path objects in return values to prevent side effects that caused unit tests to fail on some platforms * poe format * Attempt to bypass getcwd errors in CI with patch * Consistently use strings for paths instead of some strings and some pathlib.Path * Keep pathlib within a function for readability * fix for ruamel.yaml versions >=0.17.22 * Run poe format --------- Co-authored-by: Jonathan Wren <jonathan@nowandwren.com>
This commit is contained in:
parent
78d11d74bd
commit
4a7057c038
11 changed files with 190 additions and 147 deletions
|
@ -4,12 +4,10 @@
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
import colorama
|
import colorama
|
||||||
import xdg.BaseDirectory
|
|
||||||
from rich.pretty import pretty_repr
|
from rich.pretty import pretty_repr
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
from ruamel.yaml import constructor
|
from ruamel.yaml import constructor
|
||||||
|
@ -21,13 +19,10 @@ from jrnl.messages import MsgStyle
|
||||||
from jrnl.messages import MsgText
|
from jrnl.messages import MsgText
|
||||||
from jrnl.output import list_journals
|
from jrnl.output import list_journals
|
||||||
from jrnl.output import print_msg
|
from jrnl.output import print_msg
|
||||||
from jrnl.path import home_dir
|
from jrnl.path import get_config_path
|
||||||
|
from jrnl.path import get_default_journal_path
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
DEFAULT_CONFIG_NAME = "jrnl.yaml"
|
|
||||||
XDG_RESOURCE = "jrnl"
|
|
||||||
|
|
||||||
DEFAULT_JOURNAL_NAME = "journal.txt"
|
|
||||||
DEFAULT_JOURNAL_KEY = "default"
|
DEFAULT_JOURNAL_KEY = "default"
|
||||||
|
|
||||||
YAML_SEPARATOR = ": "
|
YAML_SEPARATOR = ": "
|
||||||
|
@ -73,31 +68,6 @@ def save_config(config: dict, alt_config_path: str | None = None) -> None:
|
||||||
yaml.dump(config, f)
|
yaml.dump(config, f)
|
||||||
|
|
||||||
|
|
||||||
def get_config_directory() -> str:
|
|
||||||
try:
|
|
||||||
return xdg.BaseDirectory.save_config_path(XDG_RESOURCE)
|
|
||||||
except FileExistsError:
|
|
||||||
raise JrnlException(
|
|
||||||
Message(
|
|
||||||
MsgText.ConfigDirectoryIsFile,
|
|
||||||
MsgStyle.ERROR,
|
|
||||||
{
|
|
||||||
"config_directory_path": os.path.join(
|
|
||||||
xdg.BaseDirectory.xdg_config_home, XDG_RESOURCE
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_config_path() -> Path:
|
|
||||||
try:
|
|
||||||
config_directory_path = get_config_directory()
|
|
||||||
except JrnlException:
|
|
||||||
return Path(home_dir(), DEFAULT_CONFIG_NAME)
|
|
||||||
return Path(config_directory_path, DEFAULT_CONFIG_NAME)
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_config() -> dict[str, Any]:
|
def get_default_config() -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"version": __version__,
|
"version": __version__,
|
||||||
|
@ -130,20 +100,6 @@ def get_default_colors() -> dict[str, Any]:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_default_journal_path() -> str:
|
|
||||||
journal_data_path = xdg.BaseDirectory.save_data_path(XDG_RESOURCE) or home_dir()
|
|
||||||
return os.path.join(journal_data_path, DEFAULT_JOURNAL_NAME)
|
|
||||||
|
|
||||||
|
|
||||||
def get_templates_path() -> Path:
|
|
||||||
# jrnl_xdg_resource_path is created by save_data_path if it does not exist
|
|
||||||
jrnl_xdg_resource_path = Path(xdg.BaseDirectory.save_data_path(XDG_RESOURCE))
|
|
||||||
jrnl_templates_path = jrnl_xdg_resource_path / "templates"
|
|
||||||
# Create the directory if needed.
|
|
||||||
jrnl_templates_path.mkdir(exist_ok=True)
|
|
||||||
return jrnl_templates_path
|
|
||||||
|
|
||||||
|
|
||||||
def scope_config(config: dict, journal_name: str) -> dict:
|
def scope_config(config: dict, journal_name: str) -> dict:
|
||||||
if journal_name not in config["journals"]:
|
if journal_name not in config["journals"]:
|
||||||
return config
|
return config
|
||||||
|
|
|
@ -11,10 +11,10 @@ from jrnl import time
|
||||||
from jrnl.config import DEFAULT_JOURNAL_KEY
|
from jrnl.config import DEFAULT_JOURNAL_KEY
|
||||||
from jrnl.config import get_config_path
|
from jrnl.config import get_config_path
|
||||||
from jrnl.config import get_journal_name
|
from jrnl.config import get_journal_name
|
||||||
from jrnl.config import get_templates_path
|
|
||||||
from jrnl.config import scope_config
|
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.editor import read_template_file
|
||||||
from jrnl.exception import JrnlException
|
from jrnl.exception import JrnlException
|
||||||
from jrnl.journals import open_journal
|
from jrnl.journals import open_journal
|
||||||
from jrnl.messages import Message
|
from jrnl.messages import Message
|
||||||
|
@ -23,7 +23,6 @@ from jrnl.messages import MsgText
|
||||||
from jrnl.output import print_msg
|
from jrnl.output import print_msg
|
||||||
from jrnl.output import print_msgs
|
from jrnl.output import print_msgs
|
||||||
from jrnl.override import apply_overrides
|
from jrnl.override import apply_overrides
|
||||||
from jrnl.path import absolute_path
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
|
@ -130,74 +129,6 @@ def _is_append_mode(args: "Namespace", config: dict, **kwargs) -> bool:
|
||||||
return append_mode
|
return append_mode
|
||||||
|
|
||||||
|
|
||||||
def _read_template_file(template_arg: str, template_path_from_config: str) -> str:
|
|
||||||
"""
|
|
||||||
This function is called when either a template file is passed with --template, or config.template is set.
|
|
||||||
|
|
||||||
The processing logic is:
|
|
||||||
If --template was not used: Load the global template file.
|
|
||||||
If --template was used:
|
|
||||||
* Check $XDG_DATA_HOME/jrnl/templates/template_arg.
|
|
||||||
* Check template_arg as an absolute / relative path.
|
|
||||||
|
|
||||||
If a file is found, its contents are returned as a string.
|
|
||||||
If not, a JrnlException is raised.
|
|
||||||
"""
|
|
||||||
logging.debug(
|
|
||||||
"Append mode: Either a template arg was passed, or the global config is set."
|
|
||||||
)
|
|
||||||
|
|
||||||
# If filename is unset, we are in this flow due to a global template being configured
|
|
||||||
if not template_arg:
|
|
||||||
logging.debug("Append mode: Global template configuration detected.")
|
|
||||||
global_template_path = absolute_path(template_path_from_config)
|
|
||||||
try:
|
|
||||||
with open(global_template_path, encoding="utf-8") as f:
|
|
||||||
template_data = f.read()
|
|
||||||
return template_data
|
|
||||||
except FileNotFoundError:
|
|
||||||
raise JrnlException(
|
|
||||||
Message(
|
|
||||||
MsgText.CantReadTemplateGlobalConfig,
|
|
||||||
MsgStyle.ERROR,
|
|
||||||
{
|
|
||||||
"global_template_path": global_template_path,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else: # A template CLI arg was passed.
|
|
||||||
logging.debug("Trying to load template from $XDG_DATA_HOME/jrnl/templates/")
|
|
||||||
jrnl_template_dir = get_templates_path()
|
|
||||||
logging.debug(f"Append mode: jrnl templates directory: {jrnl_template_dir}")
|
|
||||||
template_path = jrnl_template_dir / template_arg
|
|
||||||
try:
|
|
||||||
with open(template_path, encoding="utf-8") as f:
|
|
||||||
template_data = f.read()
|
|
||||||
return template_data
|
|
||||||
except FileNotFoundError:
|
|
||||||
logging.debug(
|
|
||||||
f"Couldn't open {template_path}. Treating --template argument like a local / abs path."
|
|
||||||
)
|
|
||||||
pass
|
|
||||||
|
|
||||||
normalized_template_arg_filepath = absolute_path(template_arg)
|
|
||||||
try:
|
|
||||||
with open(normalized_template_arg_filepath, encoding="utf-8") as f:
|
|
||||||
template_data = f.read()
|
|
||||||
return template_data
|
|
||||||
except FileNotFoundError:
|
|
||||||
raise JrnlException(
|
|
||||||
Message(
|
|
||||||
MsgText.CantReadTemplateCLIArg,
|
|
||||||
MsgStyle.ERROR,
|
|
||||||
{
|
|
||||||
"normalized_template_arg_filepath": normalized_template_arg_filepath,
|
|
||||||
"jrnl_template_dir": template_path,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -> None:
|
def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
Gets input from the user to write to the journal
|
Gets input from the user to write to the journal
|
||||||
|
@ -210,26 +141,22 @@ def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -
|
||||||
"""
|
"""
|
||||||
logging.debug("Append mode: starting")
|
logging.debug("Append mode: starting")
|
||||||
|
|
||||||
if args.template or config["template"]:
|
template_text = _get_template(args, config)
|
||||||
logging.debug(f"Append mode: template CLI arg detected: {args.template}")
|
|
||||||
# Read template file and pass as raw text into the composer
|
if args.text:
|
||||||
template_data = _read_template_file(args.template, config["template"])
|
|
||||||
raw = _write_in_editor(config, template_data)
|
|
||||||
if raw == template_data:
|
|
||||||
logging.error("Append mode: raw text was the same as the template")
|
|
||||||
raise JrnlException(Message(MsgText.NoChangesToTemplate, MsgStyle.NORMAL))
|
|
||||||
elif args.text:
|
|
||||||
logging.debug(f"Append mode: cli text detected: {args.text}")
|
logging.debug(f"Append mode: cli text detected: {args.text}")
|
||||||
raw = " ".join(args.text).strip()
|
raw = " ".join(args.text).strip()
|
||||||
if args.edit:
|
if args.edit:
|
||||||
raw = _write_in_editor(config, raw)
|
raw = _write_in_editor(config, raw)
|
||||||
|
|
||||||
elif not sys.stdin.isatty():
|
elif not sys.stdin.isatty():
|
||||||
logging.debug("Append mode: receiving piped text")
|
logging.debug("Append mode: receiving piped text")
|
||||||
raw = sys.stdin.read()
|
raw = sys.stdin.read()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raw = _write_in_editor(config)
|
raw = _write_in_editor(config, template_text)
|
||||||
|
|
||||||
|
if template_text is not None and raw == template_text:
|
||||||
|
logging.error("Append mode: raw text was the same as the template")
|
||||||
|
raise JrnlException(Message(MsgText.NoChangesToTemplate, MsgStyle.NORMAL))
|
||||||
|
|
||||||
if not raw or raw.isspace():
|
if not raw or raw.isspace():
|
||||||
logging.error("Append mode: couldn't get raw text or entry was empty")
|
logging.error("Append mode: couldn't get raw text or entry was empty")
|
||||||
|
@ -251,6 +178,21 @@ def append_mode(args: "Namespace", config: dict, journal: "Journal", **kwargs) -
|
||||||
logging.debug("Append mode: completed journal.write()")
|
logging.debug("Append mode: completed journal.write()")
|
||||||
|
|
||||||
|
|
||||||
|
def _get_template(args, config) -> str:
|
||||||
|
# Read template file and pass as raw text into the composer
|
||||||
|
logging.debug(
|
||||||
|
f"Get template:\n--template: {args.template}\nfrom config: {config.get('template')}"
|
||||||
|
)
|
||||||
|
template_path = args.template or config.get("template")
|
||||||
|
|
||||||
|
template_text = None
|
||||||
|
|
||||||
|
if template_path:
|
||||||
|
template_text = read_template_file(template_path)
|
||||||
|
|
||||||
|
return template_text
|
||||||
|
|
||||||
|
|
||||||
def search_mode(args: "Namespace", journal: "Journal", **kwargs) -> None:
|
def search_mode(args: "Namespace", journal: "Journal", **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
Search for entries in a journal, and return the
|
Search for entries in a journal, and return the
|
||||||
|
|
|
@ -15,6 +15,8 @@ from jrnl.messages import MsgText
|
||||||
from jrnl.os_compat import on_windows
|
from jrnl.os_compat import on_windows
|
||||||
from jrnl.os_compat import split_args
|
from jrnl.os_compat import split_args
|
||||||
from jrnl.output import print_msg
|
from jrnl.output import print_msg
|
||||||
|
from jrnl.path import absolute_path
|
||||||
|
from jrnl.path import get_templates_path
|
||||||
|
|
||||||
|
|
||||||
def get_text_from_editor(config: dict, template: str = "") -> str:
|
def get_text_from_editor(config: dict, template: str = "") -> str:
|
||||||
|
@ -73,3 +75,46 @@ def get_text_from_stdin() -> str:
|
||||||
)
|
)
|
||||||
|
|
||||||
return raw
|
return raw
|
||||||
|
|
||||||
|
|
||||||
|
def get_template_path(template_path: str, jrnl_template_dir: str) -> str:
|
||||||
|
actual_template_path = os.path.join(jrnl_template_dir, template_path)
|
||||||
|
if not os.path.exists(actual_template_path):
|
||||||
|
logging.debug(
|
||||||
|
f"Couldn't open {actual_template_path}. Treating template path like a local / abs path."
|
||||||
|
)
|
||||||
|
actual_template_path = absolute_path(template_path)
|
||||||
|
|
||||||
|
return actual_template_path
|
||||||
|
|
||||||
|
|
||||||
|
def read_template_file(template_path: str) -> str:
|
||||||
|
"""
|
||||||
|
Reads the template file given a template path in this order:
|
||||||
|
|
||||||
|
* Check $XDG_DATA_HOME/jrnl/templates/template_path.
|
||||||
|
* Check template_arg as an absolute / relative path.
|
||||||
|
|
||||||
|
If a file is found, its contents are returned as a string.
|
||||||
|
If not, a JrnlException is raised.
|
||||||
|
"""
|
||||||
|
|
||||||
|
jrnl_template_dir = get_templates_path()
|
||||||
|
actual_template_path = get_template_path(template_path, jrnl_template_dir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(actual_template_path, encoding="utf-8") as f:
|
||||||
|
template_data = f.read()
|
||||||
|
return template_data
|
||||||
|
except FileNotFoundError:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.CantReadTemplate,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{
|
||||||
|
"template_path": template_path,
|
||||||
|
"actual_template_path": actual_template_path,
|
||||||
|
"jrnl_template_dir": str(jrnl_template_dir) + os.sep,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -105,16 +105,12 @@ class MsgText(Enum):
|
||||||
|
|
||||||
KeyboardInterruptMsg = "Aborted by user"
|
KeyboardInterruptMsg = "Aborted by user"
|
||||||
|
|
||||||
CantReadTemplateGlobalConfig = """
|
CantReadTemplate = """
|
||||||
Could not read template file defined in config:
|
Unable to find a template file {template_path}.
|
||||||
{global_template_path}
|
|
||||||
"""
|
|
||||||
|
|
||||||
CantReadTemplateCLIArg = """
|
The following paths were checked:
|
||||||
Unable to find a template file based on the passed arg, and no global template was detected.
|
* {jrnl_template_dir}{template_path}
|
||||||
The following filepaths were checked:
|
* {actual_template_path}
|
||||||
jrnl XDG Template Directory : {jrnl_template_dir}
|
|
||||||
Local Filepath : {normalized_template_arg_filepath}
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
NoNamedJournal = "No '{journal_name}' journal configured\n{journals}"
|
NoNamedJournal = "No '{journal_name}' journal configured\n{journals}"
|
||||||
|
|
|
@ -39,7 +39,10 @@ def journal_list_to_yaml(journal_list: dict) -> str:
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
YAML().dump(journal_list, output)
|
dumper = YAML()
|
||||||
|
dumper.width = 1000
|
||||||
|
dumper.dump(journal_list, output)
|
||||||
|
|
||||||
return output.getvalue()
|
return output.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
|
56
jrnl/path.py
56
jrnl/path.py
|
@ -2,6 +2,19 @@
|
||||||
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import xdg.BaseDirectory
|
||||||
|
|
||||||
|
from jrnl.exception import JrnlException
|
||||||
|
from jrnl.messages import Message
|
||||||
|
from jrnl.messages import MsgStyle
|
||||||
|
from jrnl.messages import MsgText
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
XDG_RESOURCE = "jrnl"
|
||||||
|
DEFAULT_CONFIG_NAME = "jrnl.yaml"
|
||||||
|
DEFAULT_JOURNAL_NAME = "journal.txt"
|
||||||
|
|
||||||
|
|
||||||
def home_dir() -> str:
|
def home_dir() -> str:
|
||||||
|
@ -14,3 +27,46 @@ def expand_path(path: str) -> str:
|
||||||
|
|
||||||
def absolute_path(path: str) -> str:
|
def absolute_path(path: str) -> str:
|
||||||
return os.path.abspath(expand_path(path))
|
return os.path.abspath(expand_path(path))
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_journal_path() -> str:
|
||||||
|
journal_data_path = xdg.BaseDirectory.save_data_path(XDG_RESOURCE) or home_dir()
|
||||||
|
return os.path.join(journal_data_path, DEFAULT_JOURNAL_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
def get_templates_path() -> str:
|
||||||
|
"""
|
||||||
|
Get the path to the XDG templates directory. Creates the directory if it
|
||||||
|
doesn't exist.
|
||||||
|
"""
|
||||||
|
# jrnl_xdg_resource_path is created by save_data_path if it does not exist
|
||||||
|
jrnl_xdg_resource_path = Path(xdg.BaseDirectory.save_data_path(XDG_RESOURCE))
|
||||||
|
jrnl_templates_path = jrnl_xdg_resource_path / "templates"
|
||||||
|
# Create the directory if needed.
|
||||||
|
jrnl_templates_path.mkdir(exist_ok=True)
|
||||||
|
return str(jrnl_templates_path)
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_directory() -> str:
|
||||||
|
try:
|
||||||
|
return xdg.BaseDirectory.save_config_path(XDG_RESOURCE)
|
||||||
|
except FileExistsError:
|
||||||
|
raise JrnlException(
|
||||||
|
Message(
|
||||||
|
MsgText.ConfigDirectoryIsFile,
|
||||||
|
MsgStyle.ERROR,
|
||||||
|
{
|
||||||
|
"config_directory_path": os.path.join(
|
||||||
|
xdg.BaseDirectory.xdg_config_home, XDG_RESOURCE
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_path() -> str:
|
||||||
|
try:
|
||||||
|
config_directory_path = get_config_directory()
|
||||||
|
except JrnlException:
|
||||||
|
return os.path.join(home_dir(), DEFAULT_CONFIG_NAME)
|
||||||
|
return os.path.join(config_directory_path, DEFAULT_CONFIG_NAME)
|
||||||
|
|
10
poetry.lock
generated
10
poetry.lock
generated
|
@ -1598,18 +1598,18 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruamel-yaml"
|
name = "ruamel-yaml"
|
||||||
version = "0.17.21"
|
version = "0.17.24"
|
||||||
description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
|
description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3"
|
python-versions = ">=3"
|
||||||
files = [
|
files = [
|
||||||
{file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"},
|
{file = "ruamel.yaml-0.17.24-py3-none-any.whl", hash = "sha256:f251bd9096207af604af69d6495c3c650a3338d0493d27b04bc55477d7a884ed"},
|
||||||
{file = "ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af"},
|
{file = "ruamel.yaml-0.17.24.tar.gz", hash = "sha256:90e398ee24524ebe20fc48cd1861cedd25520457b9a36cfb548613e57fde30a0"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
"ruamel.yaml.clib" = {version = ">=0.2.6", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}
|
"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.12\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["ryd"]
|
docs = ["ryd"]
|
||||||
|
@ -1953,4 +1953,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.10.0, <3.13"
|
python-versions = ">=3.10.0, <3.13"
|
||||||
content-hash = "1306520c524e8cf20ca672e3b77eb0aa1fcc67e5994c86bd99a293415a0795b8"
|
content-hash = "037329f79e6d33799cf05f4c71e15ea17368143eeb5e31adf59325c44e46fb45"
|
||||||
|
|
|
@ -36,7 +36,7 @@ keyring = ">=21.0" # https://github.com/jaraco/keyring#integration
|
||||||
parsedatetime = ">=2.6"
|
parsedatetime = ">=2.6"
|
||||||
python-dateutil = "^2.8" # https://github.com/dateutil/dateutil/blob/master/RELEASING
|
python-dateutil = "^2.8" # https://github.com/dateutil/dateutil/blob/master/RELEASING
|
||||||
pyxdg = ">=0.27.0"
|
pyxdg = ">=0.27.0"
|
||||||
"ruamel.yaml" = "0.17.21" # locked to this version until bug is resolved: https://github.com/jrnl-org/jrnl/issues/1736
|
"ruamel.yaml" = ">=0.17.22"
|
||||||
rich = ">=12.2.0, <14.0.0"
|
rich = ">=12.2.0, <14.0.0"
|
||||||
|
|
||||||
# dayone-only deps
|
# dayone-only deps
|
||||||
|
|
|
@ -38,7 +38,7 @@ Feature: Using templates
|
||||||
And we use the password "test" if prompted
|
And we use the password "test" if prompted
|
||||||
When we run "jrnl --template this_template_does_not_exist.template"
|
When we run "jrnl --template this_template_does_not_exist.template"
|
||||||
Then we should get an error
|
Then we should get an error
|
||||||
Then the error output should contain "Unable to find a template file based on the passed arg"
|
Then the error output should contain "Unable to find a template file"
|
||||||
|
|
||||||
Examples: configs
|
Examples: configs
|
||||||
| config_file |
|
| config_file |
|
||||||
|
|
|
@ -183,10 +183,10 @@ def mock_default_journal_path(temp_dir):
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
def mock_default_templates_path(temp_dir):
|
def mock_default_templates_path(temp_dir):
|
||||||
templates_path = Path(temp_dir.name, "templates")
|
templates_path = os.path.join(temp_dir.name, "templates")
|
||||||
return {
|
return {
|
||||||
"get_templates_path": lambda: patch(
|
"get_templates_path": lambda: patch(
|
||||||
"jrnl.controller.get_templates_path", return_value=templates_path
|
"jrnl.editor.get_templates_path", return_value=templates_path
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
45
tests/unit/test_editor.py
Normal file
45
tests/unit/test_editor.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# Copyright © 2012-2023 jrnl contributors
|
||||||
|
# License: https://www.gnu.org/licenses/gpl-3.0.html
|
||||||
|
|
||||||
|
import os
|
||||||
|
from unittest.mock import mock_open
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from jrnl.editor import get_template_path
|
||||||
|
from jrnl.editor import read_template_file
|
||||||
|
from jrnl.exception import JrnlException
|
||||||
|
|
||||||
|
|
||||||
|
@patch(
|
||||||
|
"os.getcwd", side_effect="/"
|
||||||
|
) # prevent failures in CI if current directory has been deleted
|
||||||
|
@patch("builtins.open", side_effect=FileNotFoundError())
|
||||||
|
def test_read_template_file_with_no_file_raises_exception(mock_open, mock_getcwd):
|
||||||
|
with pytest.raises(JrnlException) as ex:
|
||||||
|
read_template_file("invalid_file.txt")
|
||||||
|
assert isinstance(ex.value, JrnlException)
|
||||||
|
|
||||||
|
|
||||||
|
@patch(
|
||||||
|
"os.getcwd", side_effect="/"
|
||||||
|
) # prevent failures in CI if current directory has been deleted
|
||||||
|
@patch("builtins.open", new_callable=mock_open, read_data="template text")
|
||||||
|
def test_read_template_file_with_valid_file_returns_text(mock_file, mock_getcwd):
|
||||||
|
assert read_template_file("valid_file.txt") == "template text"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_template_path_when_exists_returns_correct_path():
|
||||||
|
with patch("os.path.exists", return_value=True):
|
||||||
|
output = get_template_path("template", "templatepath")
|
||||||
|
|
||||||
|
assert output == os.path.join("templatepath", "template")
|
||||||
|
|
||||||
|
|
||||||
|
@patch("jrnl.editor.absolute_path")
|
||||||
|
def test_get_template_path_when_doesnt_exist_returns_correct_path(mock_absolute_paths):
|
||||||
|
with patch("os.path.exists", return_value=False):
|
||||||
|
output = get_template_path("template", "templatepath")
|
||||||
|
|
||||||
|
assert output == mock_absolute_paths.return_value
|
Loading…
Add table
Reference in a new issue