diff --git a/TODO.todo b/TODO.todo index f7c5ce0..ef1f800 100644 --- a/TODO.todo +++ b/TODO.todo @@ -20,6 +20,22 @@ Documentation: ☐ Document how to use pytest to read a logging message + - caplog as fixture + - reading `caplog.records[0].message` + see `_old_test_pages.py` + + ☐ Document testing value of an exception raised + When you use `with pytest.raises` you can use `.value` to access the attributes + reading `.value.code` + reading `str(.value)` + + ☐ Document working with exceptions + ☐ General pattern - raise exceptions in codebase, catch them in the CLI. + Allows people to use via an API and handle the exceptions themselves. + You can use python builtins but custom exceptions are better for internal control + ☐ Capturing exceptions in the CLI. + Access the message of the exception with `.args[0]`. + use `raise SystemExit(1) from exception` in order to gracefully exit ☐ 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 diff --git a/tembo/cli.py b/tembo/cli.py index a1f8313..c2e3f5e 100644 --- a/tembo/cli.py +++ b/tembo/cli.py @@ -2,6 +2,7 @@ import click import tembo from tembo.journal import pages +from tembo import exceptions CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) @@ -112,7 +113,15 @@ def new(scope, inputs, dry_run, example): template_path=tembo.CONFIG.template_path, ) if _name_found: - scoped_page = pages.ScopedPageCreator().create_page(page_creator_options) + try: + scoped_page = pages.ScopedPageCreator().create_page(page_creator_options) + except exceptions.BasePathDoesNotExistError as base_path_does_not_exist_error: + tembo.logger.critical(base_path_does_not_exist_error) + raise SystemExit(1) from base_path_does_not_exist_error + except exceptions.TemplateFileNotFoundError as template_file_not_found_error: + tembo.logger.critical(template_file_not_found_error.args[0]) + raise SystemExit(1) from template_file_not_found_error + scoped_page.save_to_disk(dry_run=dry_run) raise SystemExit(0) if not _name_found and len(tembo.CONFIG.scopes) > 0: diff --git a/tembo/exceptions.py b/tembo/exceptions.py index 9746128..d4b0252 100644 --- a/tembo/exceptions.py +++ b/tembo/exceptions.py @@ -6,4 +6,8 @@ class MismatchedTokenError(Exception): class BasePathDoesNotExistError(Exception): - pass + """Raised if the base path does not exist.""" + + +class TemplateFileNotFoundError(Exception): + """Raised if the template file does not exist.""" diff --git a/tembo/journal/pages.py b/tembo/journal/pages.py index 4870b47..b566c6b 100644 --- a/tembo/journal/pages.py +++ b/tembo/journal/pages.py @@ -11,6 +11,7 @@ import jinja2 from jinja2.exceptions import TemplateNotFound import tembo +from tembo import exceptions # TODO: flesh this out with details for the optional args @@ -57,10 +58,9 @@ class PageCreator: def _convert_base_path_to_path(self) -> pathlib.Path: # check if Tembo base path exists if not pathlib.Path(self.options.base_path).expanduser().exists(): - tembo.logger.critical( - "Tembo base path of %s does not exist - exiting", self.options.base_path + raise exceptions.BasePathDoesNotExistError( + f"Tembo base path of {self.options.base_path} does not exist." ) - raise SystemExit(1) path_to_file = ( pathlib.Path(self.options.base_path).expanduser() / pathlib.Path(self.options.page_path.replace(" ", "_")).expanduser() @@ -74,6 +74,7 @@ class PageCreator: else self.options.extension ) except IndexError: + # REVIEW: can this be removed now this is not called anywhere else? # IndexError means the path is not a file, just a path return path_to_file # return path with a file @@ -91,14 +92,14 @@ class PageCreator: file_loader = jinja2.FileSystemLoader(converted_template_path) env = jinja2.Environment(loader=file_loader, autoescape=True) + try: loaded_template = env.get_template(self.options.template_filename) except TemplateNotFound as template_not_found: - tembo.logger.critical( - "Template file %s not found - exiting", - str(self.options.template_path) + "/" + str(template_not_found.message), - ) - raise SystemExit(1) from template_not_found + _template_file = f"{converted_template_path}/{template_not_found.args[0]}" + raise exceptions.TemplateFileNotFoundError( + f"Template file {_template_file} does not exist." + ) from template_not_found return loaded_template.render() diff --git a/tests/test_journal/test_pages.py b/tests/test_journal/test_pages.py index d751287..16b4d54 100644 --- a/tests/test_journal/test_pages.py +++ b/tests/test_journal/test_pages.py @@ -1,9 +1,10 @@ import pytest from tembo.journal.pages import PageCreatorOptions, ScopedPageCreator +from tembo.exceptions import BasePathDoesNotExistError -def test_create_page_base_path_does_not_exist(tmpdir, caplog): +def test_create_page_base_path_does_not_exist(tmpdir): # arrange base_path = str(tmpdir / "nonexistent" / "path") options = PageCreatorOptions( @@ -19,13 +20,11 @@ def test_create_page_base_path_does_not_exist(tmpdir, caplog): ) # act - with pytest.raises(SystemExit) as system_exit: + with pytest.raises(BasePathDoesNotExistError) as base_path_does_not_exist_error: scoped_page_creator = ScopedPageCreator().create_page(options) # assert - assert system_exit.value.code == 1 assert ( - caplog.records[0].message - == f"Tembo base path of {base_path} does not exist - exiting" + str(base_path_does_not_exist_error.value) + == f"Tembo base path of {base_path} does not exist." ) - assert caplog.records[0].levelname == "CRITICAL"