mirror of
https://github.com/dtomlinson91/tembo.git
synced 2025-12-22 09:45:44 +00:00
Merge branch 'refactor/optional_user_inputs' into develop
This commit is contained in:
27
TODO.todo
27
TODO.todo
@@ -1,7 +1,4 @@
|
|||||||
Priority:
|
Priority:
|
||||||
✔ Document the python/logging/typing in Trilium @done(21-10-25 14:33)
|
|
||||||
✔ Update typing annotations to include generics instead @done(21-10-25 22:38)
|
|
||||||
https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes
|
|
||||||
☐ Write the tests
|
☐ Write the tests
|
||||||
☐ test logs: <https://stackoverflow.com/questions/53125305/testing-logging-output-with-pytest>
|
☐ test logs: <https://stackoverflow.com/questions/53125305/testing-logging-output-with-pytest>
|
||||||
document this
|
document this
|
||||||
@@ -25,17 +22,14 @@ Documentation:
|
|||||||
<https://stackoverflow.com/questions/53125305/testing-logging-output-with-pytest>
|
<https://stackoverflow.com/questions/53125305/testing-logging-output-with-pytest>
|
||||||
|
|
||||||
☐ Document using datadir with a module rather than a shared one. Link to tembo as an example.
|
☐ Document using datadir with a module rather than a shared one. Link to tembo as an example.
|
||||||
|
☐ Can prospector ignore tests dir? document this in the gist if so
|
||||||
|
|
||||||
Functionality:
|
Functionality:
|
||||||
✔ Move any `tembo.CONFIG` calls out of `pages.py` and ensure these are passed in from the cli. @done(21-10-28 19:44)
|
|
||||||
✔ Make `config scope` a dict in `cli.py`. @done(21-10-28 19:44)
|
|
||||||
✔ Make example optional @done(21-10-29 00:15)
|
|
||||||
✔ Add the `--example` output to the miscounted token message so the user knows the correct command to use. @done(21-10-29 00:15)
|
|
||||||
✔ Page options dataclass @done(21-10-28 20:09)
|
|
||||||
☐ Replace loggers with `click.echo` for command outputs. Keep logging messages for actual logging messages?
|
☐ Replace loggers with `click.echo` for command outputs. Keep logging messages for actual logging messages?
|
||||||
☐ Look at `_convert_to_path()` and see if it can be rewritten to make it clearer when there isn't a base path.
|
☐ Refactor the tembo new command so the cli is split out into manageable methods
|
||||||
Currently checks to see if base_path is not None but this is never the case as a string must be passed in and if there isn't a base_path we pass in an empty string.
|
☐ Use the complicated CLI example so the tembo new has its own module to define functions in
|
||||||
☐ Replace scoped page creator inputs so that the whole class uses the options dict rather than the variables passed around.
|
☐ Replace all logger errors with exceptions, move logger messages to the cli.
|
||||||
|
✔ Make options a property on the class, add to abstract @done(21-10-30 19:31)
|
||||||
☐ Use the python runner Duty
|
☐ Use the python runner Duty
|
||||||
<https://github.com/pawamoy/duty>
|
<https://github.com/pawamoy/duty>
|
||||||
☐ Run tests
|
☐ Run tests
|
||||||
@@ -74,6 +68,17 @@ Logging:
|
|||||||
clone the repo, delete .git, git init, configure and add git origin
|
clone the repo, delete .git, git init, configure and add git origin
|
||||||
|
|
||||||
Archive:
|
Archive:
|
||||||
|
✔ Document the python/logging/typing in Trilium @done(21-10-25 14:33) @project(Priority)
|
||||||
|
✔ Update typing annotations to include generics instead @done(21-10-25 22:38) @project(Priority)
|
||||||
|
https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes
|
||||||
|
✔ Move any `tembo.CONFIG` calls out of `pages.py` and ensure these are passed in from the cli. @done(21-10-28 19:44) @project(Functionality)
|
||||||
|
✔ Make `config scope` a dict in `cli.py`. @done(21-10-28 19:44) @project(Functionality)
|
||||||
|
✔ Make example optional @done(21-10-29 00:15) @project(Functionality)
|
||||||
|
✔ Add the `--example` output to the miscounted token message so the user knows the correct command to use. @done(21-10-29 00:15) @project(Functionality)
|
||||||
|
✔ Page options dataclass @done(21-10-28 20:09) @project(Functionality)
|
||||||
|
✔ Make user_input optional @important @done(21-10-30 03:20) @project(Functionality)
|
||||||
|
✔ Look at `_convert_to_path()` and see if it can be rewritten to make it clearer when there isn't a base path. @done(21-10-30 02:14) @project(Functionality)
|
||||||
|
✔ Replace scoped page creator inputs so that the whole class uses the options dict rather than the variables passed around. @done(21-10-30 03:20) @project(Functionality)
|
||||||
✔ Go through code TODOs @done(21-10-25 05:52) @project(Priority)
|
✔ Go through code TODOs @done(21-10-25 05:52) @project(Priority)
|
||||||
✔ Check code order and make sure things are where they should be @done(21-10-25 13:31) @project(Priority)
|
✔ Check code order and make sure things are where they should be @done(21-10-25 13:31) @project(Priority)
|
||||||
✔ Add version option @done(21-10-25 13:40) @project(Functionality)
|
✔ Add version option @done(21-10-25 13:40) @project(Functionality)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
# testing notes
|
# testing notes
|
||||||
|
|
||||||
optional:
|
optional:
|
||||||
- template_path
|
- user_input
|
||||||
- example
|
- example
|
||||||
- template_filename
|
- template_filename
|
||||||
|
- template_path
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- base_path
|
- base_path
|
||||||
@@ -11,20 +12,46 @@ required:
|
|||||||
- filename
|
- filename
|
||||||
- extension
|
- extension
|
||||||
- name
|
- name
|
||||||
- user_input - should be optional
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- page with a template
|
|
||||||
- page without a template
|
|
||||||
- page using date tokens
|
|
||||||
- page using input tokens
|
|
||||||
- page using name tokens
|
|
||||||
|
|
||||||
|
|
||||||
|
- page with/without a template
|
||||||
|
- user input is None
|
||||||
|
- the given base path does not exist
|
||||||
|
- page using/not using input tokens
|
||||||
- user input does not match number of input tokens
|
- user input does not match number of input tokens
|
||||||
|
- no user input
|
||||||
|
- mismatched user input
|
||||||
|
- with/without example
|
||||||
|
- page using/not using date tokens
|
||||||
|
- page using/not using name tokens
|
||||||
|
|
||||||
|
|
||||||
|
- path/page filenames can contain spaces and they are converted
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PageCreatorOptions:
|
||||||
|
"""Options dataclass to create a Page.
|
||||||
|
|
||||||
- user input does match number of input tokensE
|
Attributes:
|
||||||
|
base_path (str):
|
||||||
|
page_path (str):
|
||||||
|
filename (str):
|
||||||
|
extension (str):
|
||||||
|
name (str):
|
||||||
|
user_input (Collection[str] | None, optional):
|
||||||
|
example (str | None, optional):
|
||||||
|
template_filename (str | None, optional):
|
||||||
|
template_path (str | None, optional):
|
||||||
|
"""
|
||||||
|
|
||||||
|
base_path: str
|
||||||
|
page_path: str
|
||||||
|
filename: str
|
||||||
|
extension: str
|
||||||
|
name: str
|
||||||
|
user_input: Collection[str] | None = None
|
||||||
|
example: str | None = None
|
||||||
|
template_filename: str | None = None
|
||||||
|
template_path: str | None = None
|
||||||
|
|||||||
@@ -3,3 +3,7 @@
|
|||||||
|
|
||||||
class MismatchedTokenError(Exception):
|
class MismatchedTokenError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BasePathDoesNotExistError(Exception):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -13,69 +13,90 @@ from jinja2.exceptions import TemplateNotFound
|
|||||||
import tembo
|
import tembo
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: flesh this out with details for the optional args
|
||||||
@dataclass
|
@dataclass
|
||||||
class PageCreatorOptions:
|
class PageCreatorOptions:
|
||||||
|
"""Options dataclass to create a Page.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
base_path (str):
|
||||||
|
page_path (str):
|
||||||
|
filename (str):
|
||||||
|
extension (str):
|
||||||
|
name (str):
|
||||||
|
user_input (Collection[str] | None, optional):
|
||||||
|
example (str | None, optional):
|
||||||
|
template_filename (str | None, optional):
|
||||||
|
template_path (str | None, optional):
|
||||||
|
"""
|
||||||
|
|
||||||
base_path: str
|
base_path: str
|
||||||
page_path: str
|
page_path: str
|
||||||
filename: str
|
filename: str
|
||||||
extension: str
|
extension: str
|
||||||
name: str
|
name: str
|
||||||
user_input: Collection[str]
|
user_input: Collection[str] | None = None
|
||||||
example: str | None = None
|
example: str | None = None
|
||||||
template_filename: str | None = None
|
template_filename: str | None = None
|
||||||
template_path: str | None = None
|
template_path: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class PageCreator:
|
class PageCreator:
|
||||||
|
def __init__(self, options: PageCreatorOptions) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def options(self) -> PageCreatorOptions:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def create_page(self, options: PageCreatorOptions) -> Page:
|
def create_page(self, options: PageCreatorOptions) -> Page:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@staticmethod
|
def _convert_base_path_to_path(self) -> pathlib.Path:
|
||||||
def _convert_to_path(
|
|
||||||
base_path: str, page_path: str, filename: str, extension: str
|
|
||||||
) -> pathlib.Path:
|
|
||||||
# check if Tembo base path exists
|
# check if Tembo base path exists
|
||||||
if not pathlib.Path(base_path).expanduser().exists():
|
if not pathlib.Path(self.options.base_path).expanduser().exists():
|
||||||
tembo.logger.critical(
|
tembo.logger.critical(
|
||||||
"Tembo base path of %s does not exist - exiting", base_path
|
"Tembo base path of %s does not exist - exiting", self.options.base_path
|
||||||
)
|
)
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
path_to_file = (
|
path_to_file = (
|
||||||
pathlib.Path(base_path).expanduser()
|
pathlib.Path(self.options.base_path).expanduser()
|
||||||
/ pathlib.Path(page_path.replace(" ", "_")).expanduser()
|
/ pathlib.Path(self.options.page_path.replace(" ", "_")).expanduser()
|
||||||
/ filename.replace(" ", "_")
|
/ self.options.filename.replace(" ", "_")
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
# check for existing `.` in the extension
|
# check for existing `.` in the extension
|
||||||
extension = extension[1:] if extension[0] == "." else extension
|
extension = (
|
||||||
|
self.options.extension[1:]
|
||||||
|
if self.options.extension[0] == "."
|
||||||
|
else self.options.extension
|
||||||
|
)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# IndexError means the path is not a file, just a path
|
# IndexError means the path is not a file, just a path
|
||||||
return path_to_file
|
return path_to_file
|
||||||
# return path with a file
|
# return path with a file
|
||||||
return path_to_file.with_suffix(f".{extension}")
|
return path_to_file.with_suffix(f".{extension}")
|
||||||
|
|
||||||
def _load_template(
|
def _load_template(self) -> str:
|
||||||
self, base_path: str, template_filename: str, template_path: str | None
|
if self.options.template_filename is None:
|
||||||
) -> str:
|
return ""
|
||||||
# check for overriden template_path
|
if self.options.template_path is not None:
|
||||||
if template_path is not None:
|
converted_template_path = pathlib.Path(
|
||||||
converted_template_path = pathlib.Path(template_path).expanduser()
|
self.options.template_path
|
||||||
|
).expanduser()
|
||||||
else:
|
else:
|
||||||
# default template_path is base_path / .templates
|
converted_template_path = pathlib.Path()
|
||||||
converted_template_path = self._convert_to_path(
|
|
||||||
base_path, ".templates", "", ""
|
|
||||||
)
|
|
||||||
# load the template folder
|
|
||||||
file_loader = jinja2.FileSystemLoader(converted_template_path)
|
file_loader = jinja2.FileSystemLoader(converted_template_path)
|
||||||
env = jinja2.Environment(loader=file_loader, autoescape=True)
|
env = jinja2.Environment(loader=file_loader, autoescape=True)
|
||||||
# load the template contents
|
|
||||||
try:
|
try:
|
||||||
loaded_template = env.get_template(template_filename)
|
loaded_template = env.get_template(self.options.template_filename)
|
||||||
except TemplateNotFound as template_not_found:
|
except TemplateNotFound as template_not_found:
|
||||||
tembo.logger.critical(
|
tembo.logger.critical(
|
||||||
"Template file %s not found - exiting",
|
"Template file %s not found - exiting",
|
||||||
str(template_path) + "/" + str(template_not_found.message),
|
str(self.options.template_path) + "/" + str(template_not_found.message),
|
||||||
)
|
)
|
||||||
raise SystemExit(1) from template_not_found
|
raise SystemExit(1) from template_not_found
|
||||||
return loaded_template.render()
|
return loaded_template.render()
|
||||||
@@ -92,124 +113,102 @@ class ScopedPageCreator(PageCreator):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.base_path = ""
|
|
||||||
self.page_path = ""
|
|
||||||
self.filename = ""
|
|
||||||
self.extension = ""
|
|
||||||
self._all_input_tokens: list[str] = []
|
self._all_input_tokens: list[str] = []
|
||||||
|
self._options: PageCreatorOptions
|
||||||
|
|
||||||
|
@property
|
||||||
|
def options(self) -> PageCreatorOptions:
|
||||||
|
return self._options
|
||||||
|
|
||||||
def create_page(self, options: PageCreatorOptions) -> Page:
|
def create_page(self, options: PageCreatorOptions) -> Page:
|
||||||
self.base_path = options.base_path
|
self._options = options
|
||||||
self.page_path = options.page_path
|
|
||||||
self.filename = options.filename
|
|
||||||
self.extension = options.extension
|
|
||||||
|
|
||||||
# verify the user input length matches the number of input tokens in the
|
self._all_input_tokens = self._get_input_tokens()
|
||||||
# tembo config/templates
|
self._verify_input_tokens()
|
||||||
self._all_input_tokens = self._get_input_tokens(
|
|
||||||
options.template_filename, options.template_path
|
|
||||||
)
|
|
||||||
self._verify_input_tokens(options.user_input, options.example)
|
|
||||||
|
|
||||||
# get the path of the scoped page
|
path = self._convert_base_path_to_path()
|
||||||
path = self._convert_to_path(
|
path = pathlib.Path(self._substitute_tokens(str(path)))
|
||||||
self.base_path, self.page_path, self.filename, self.extension
|
|
||||||
)
|
|
||||||
|
|
||||||
# substitute tokens in the filepath
|
template_contents = self._load_template()
|
||||||
path = pathlib.Path(
|
|
||||||
self._substitute_tokens(str(path), options.user_input, options.name)
|
|
||||||
)
|
|
||||||
|
|
||||||
# get the template file
|
|
||||||
template_contents = self._get_template_contents(
|
|
||||||
options.template_filename, options.template_path
|
|
||||||
)
|
|
||||||
# substitute tokens in template_contents
|
|
||||||
if options.template_filename is not None:
|
if options.template_filename is not None:
|
||||||
template_contents = self._substitute_tokens(
|
template_contents = self._substitute_tokens(template_contents)
|
||||||
template_contents, options.user_input, options.name
|
|
||||||
)
|
|
||||||
return ScopedPage(path, template_contents)
|
return ScopedPage(path, template_contents)
|
||||||
|
|
||||||
def _get_template_contents(
|
def _get_input_tokens(self) -> list[str]:
|
||||||
self, template_filename: str | None, template_path: str | None
|
|
||||||
) -> str:
|
|
||||||
return (
|
|
||||||
self._load_template(self.base_path, template_filename, template_path)
|
|
||||||
if template_filename is not None
|
|
||||||
else ""
|
|
||||||
)
|
|
||||||
|
|
||||||
def _get_input_tokens(
|
|
||||||
self, template_filename: str | None, template_path: str | None
|
|
||||||
) -> list[str]:
|
|
||||||
path = str(
|
path = str(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
self.base_path, self.page_path, self.filename, self.extension
|
self.options.base_path,
|
||||||
|
self.options.page_path,
|
||||||
|
self.options.filename,
|
||||||
|
self.options.extension,
|
||||||
).expanduser()
|
).expanduser()
|
||||||
)
|
)
|
||||||
template_contents = self._get_template_contents(
|
template_contents = self._load_template()
|
||||||
template_filename, template_path
|
|
||||||
)
|
|
||||||
# get the input tokens from both the path and the template
|
# get the input tokens from both the path and the template
|
||||||
all_input_tokens = []
|
all_input_tokens = []
|
||||||
for tokenified_string in (path, template_contents):
|
for tokenified_string in (path, template_contents):
|
||||||
all_input_tokens.extend(re.findall(r"(\{input\d*\})", tokenified_string))
|
all_input_tokens.extend(re.findall(r"(\{input\d*\})", tokenified_string))
|
||||||
return sorted(all_input_tokens)
|
return sorted(all_input_tokens)
|
||||||
|
|
||||||
def _verify_input_tokens(
|
def _verify_input_tokens(self) -> None:
|
||||||
self, user_input: Collection[str], example: str | None
|
if len(self._all_input_tokens) > 0 and self.options.user_input is None:
|
||||||
) -> None:
|
if self.options.example is not None:
|
||||||
if len(self._all_input_tokens) != len(user_input):
|
tembo.logger.critical(
|
||||||
if example is not None:
|
"Your tembo.config/template specifies %s input tokens, you gave 0. Example command: %s",
|
||||||
|
len(self._all_input_tokens),
|
||||||
|
self.options.example,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
tembo.logger.critical(
|
||||||
|
"Your tembo.config/template specifies %s input tokens, you gave 0.",
|
||||||
|
len(self._all_input_tokens),
|
||||||
|
)
|
||||||
|
raise SystemExit(1)
|
||||||
|
if self.options.user_input is None:
|
||||||
|
return
|
||||||
|
if len(self._all_input_tokens) != len(self.options.user_input):
|
||||||
|
if self.options.example is not None:
|
||||||
tembo.logger.critical(
|
tembo.logger.critical(
|
||||||
"Your tembo.config/template specifies %s input tokens, you gave %s. Example command: %s",
|
"Your tembo.config/template specifies %s input tokens, you gave %s. Example command: %s",
|
||||||
len(self._all_input_tokens),
|
len(self._all_input_tokens),
|
||||||
len(user_input),
|
len(self.options.user_input),
|
||||||
example,
|
self.options.example,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
tembo.logger.critical(
|
tembo.logger.critical(
|
||||||
"Your tembo.config/template specifies %s input tokens, you gave %s.",
|
"Your tembo.config/template specifies %s input tokens, you gave %s.",
|
||||||
len(self._all_input_tokens),
|
len(self._all_input_tokens),
|
||||||
len(user_input),
|
len(self.options.user_input),
|
||||||
)
|
)
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
return
|
||||||
|
|
||||||
def _substitute_tokens(
|
def _substitute_tokens(self, tokenified_string: str) -> str:
|
||||||
self,
|
|
||||||
tokenified_string: str,
|
|
||||||
user_input: Collection[str],
|
|
||||||
name: str,
|
|
||||||
) -> str:
|
|
||||||
"""For a tokened string, substitute input, name and date tokens."""
|
"""For a tokened string, substitute input, name and date tokens."""
|
||||||
tokenified_string = self.__substitute_input_tokens(
|
tokenified_string = self.__substitute_input_tokens(tokenified_string)
|
||||||
tokenified_string, user_input
|
tokenified_string = self.__substitute_name_tokens(tokenified_string)
|
||||||
)
|
|
||||||
tokenified_string = self.__substitute_name_tokens(tokenified_string, name)
|
|
||||||
tokenified_string = self.__substitute_date_tokens(tokenified_string)
|
tokenified_string = self.__substitute_date_tokens(tokenified_string)
|
||||||
return tokenified_string
|
return tokenified_string
|
||||||
|
|
||||||
def __substitute_input_tokens(
|
def __substitute_input_tokens(self, tokenified_string: str) -> str:
|
||||||
self,
|
if self.options.user_input is not None:
|
||||||
tokenified_string: str,
|
for input_value, extracted_token in zip(
|
||||||
user_input: Collection[str],
|
self.options.user_input, self._all_input_tokens
|
||||||
) -> str:
|
):
|
||||||
for input_value, extracted_token in zip(user_input, self._all_input_tokens):
|
|
||||||
# REVIEW: test this for spaces in the filename/input token
|
|
||||||
tokenified_string = tokenified_string.replace(
|
tokenified_string = tokenified_string.replace(
|
||||||
extracted_token, input_value.replace(" ", "_")
|
extracted_token, input_value.replace(" ", "_")
|
||||||
)
|
)
|
||||||
return tokenified_string
|
return tokenified_string
|
||||||
|
|
||||||
@staticmethod
|
def __substitute_name_tokens(self, tokenified_string: str) -> str:
|
||||||
def __substitute_name_tokens(tokenified_string: str, name: str) -> str:
|
|
||||||
"""Find any `{name}` tokens and substitute for the name value."""
|
"""Find any `{name}` tokens and substitute for the name value."""
|
||||||
|
|
||||||
name_extraction = re.findall(r"(\{name\})", tokenified_string)
|
name_extraction = re.findall(r"(\{name\})", tokenified_string)
|
||||||
for extracted_input in name_extraction:
|
for extracted_input in name_extraction:
|
||||||
tokenified_string = tokenified_string.replace(extracted_input, name)
|
tokenified_string = tokenified_string.replace(
|
||||||
|
extracted_input, self.options.name
|
||||||
|
)
|
||||||
return tokenified_string
|
return tokenified_string
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def test_page_creator_convert_to_path_missing_base_path(caplog):
|
|||||||
|
|
||||||
# act
|
# act
|
||||||
with pytest.raises(SystemExit) as system_exit:
|
with pytest.raises(SystemExit) as system_exit:
|
||||||
PageCreator._convert_to_path(
|
PageCreator._convert_base_path_to_path(
|
||||||
base_path=base_path,
|
base_path=base_path,
|
||||||
page_path=page_path,
|
page_path=page_path,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
@@ -50,7 +50,7 @@ def test_page_creator_convert_to_path_full_path_to_file(
|
|||||||
base_path = tmpdir
|
base_path = tmpdir
|
||||||
|
|
||||||
# act
|
# act
|
||||||
converted_path = PageCreator._convert_to_path(
|
converted_path = PageCreator._convert_base_path_to_path(
|
||||||
base_path, page_path, filename, extension
|
base_path, page_path, filename, extension
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ def test_page_creator_convert_to_path_full_path_no_file(tmpdir):
|
|||||||
extension = ""
|
extension = ""
|
||||||
|
|
||||||
# act
|
# act
|
||||||
converted_path = PageCreator._convert_to_path(
|
converted_path = PageCreator._convert_base_path_to_path(
|
||||||
base_path, page_path, filename, extension
|
base_path, page_path, filename, extension
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,31 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tembo.journal.pages import PageCreatorOptions
|
from tembo.journal.pages import PageCreatorOptions, ScopedPageCreator
|
||||||
|
|
||||||
|
|
||||||
def test_scoped_page_creator_create_page_missing_base_path():
|
def test_create_page_base_path_does_not_exist(tmpdir, caplog):
|
||||||
# arrange
|
# arrange
|
||||||
options = PageCreatorOptions()
|
base_path = str(tmpdir / "nonexistent" / "path")
|
||||||
|
options = PageCreatorOptions(
|
||||||
|
base_path=base_path,
|
||||||
|
page_path="",
|
||||||
|
filename="",
|
||||||
|
extension="",
|
||||||
|
name="",
|
||||||
|
user_input=None,
|
||||||
|
example=None,
|
||||||
|
template_filename=None,
|
||||||
|
template_path=None,
|
||||||
|
)
|
||||||
|
|
||||||
# act
|
# act
|
||||||
|
with pytest.raises(SystemExit) as system_exit:
|
||||||
|
scoped_page_creator = ScopedPageCreator().create_page(options)
|
||||||
|
|
||||||
# assert
|
# assert
|
||||||
pass
|
assert system_exit.value.code == 1
|
||||||
|
assert (
|
||||||
|
caplog.records[0].message
|
||||||
|
== f"Tembo base path of {base_path} does not exist - exiting"
|
||||||
|
)
|
||||||
|
assert caplog.records[0].levelname == "CRITICAL"
|
||||||
|
|||||||
Reference in New Issue
Block a user