diff --git a/TODO.todo b/TODO.todo index d2f7949..e6f1e79 100644 --- a/TODO.todo +++ b/TODO.todo @@ -15,6 +15,7 @@ Documentation: ☐ Document regex usage ☐ Write documentation using `mkdocs` + ☐ Create a boilerplate `duties.py` for common tasks for future projects. Put in a gist. ☐ Look at how to use github actions Use for an example ☐ Build the docs using a github action. @@ -37,6 +38,9 @@ Documentation: ☐ 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 + ☐ Adding custom args to an exception + Overwrite `__init__`, access them in pytest with `.value.$args` + Access them in a try,except with `raise $excpetion as $name; $name.$arg` ☐ 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 8b8d9af..0d866e0 100644 --- a/tembo/cli.py +++ b/tembo/cli.py @@ -121,9 +121,28 @@ def new(scope, inputs, dry_run, example): 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 + except exceptions.MismatchedTokenError as mismatched_token_error: + if config_scope["example"] is not None: + tembo.logger.critical( + "Your tembo config.yml/template specifies %s input tokens, you gave %s. Example: %s", + mismatched_token_error.expected, + mismatched_token_error.given, + config_scope["example"], + ) + raise SystemExit(1) from mismatched_token_error + tembo.logger.critical( + "Your tembo config.yml/template specifies %s input tokens, you gave %s", + mismatched_token_error.expected, + mismatched_token_error.given, + ) + raise SystemExit(1) from mismatched_token_error + + if dry_run: + click.echo(cli_message(f"{scoped_page.path} will be created")) + raise SystemExit(0) try: - scoped_page.save_to_disk(dry_run=dry_run) + scoped_page.save_to_disk() raise SystemExit(0) except exceptions.ScopedPageAlreadyExists as scoped_page_already_exists: cli_message(f"File {scoped_page_already_exists}") @@ -150,7 +169,7 @@ run.add_command(list_all) if __name__ == "__main__": # new(["meeting", "robs presentation", "meeting on gcp"]) - new(["meeting", "a", "b", "c", "d"]) + new(["meeting", "a", "b", "c", "d", "e"]) # new(["meeting", "robs presentation"]) # pyinstaller diff --git a/tembo/exceptions.py b/tembo/exceptions.py index 6d9fb1b..581fcb0 100644 --- a/tembo/exceptions.py +++ b/tembo/exceptions.py @@ -2,7 +2,10 @@ class MismatchedTokenError(Exception): - pass + def __init__(self, expected: int, given: int) -> None: + self.expected = expected + self.given = given + super().__init__() class BasePathDoesNotExistError(Exception): diff --git a/tembo/journal/pages.py b/tembo/journal/pages.py index cb887eb..c7783f9 100644 --- a/tembo/journal/pages.py +++ b/tembo/journal/pages.py @@ -154,35 +154,16 @@ class ScopedPageCreator(PageCreator): def _verify_input_tokens(self) -> None: if len(self._all_input_tokens) > 0 and self.options.user_input is None: - if self.options.example is not None: - tembo.logger.critical( - "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) + raise exceptions.MismatchedTokenError( + expected=len(self._all_input_tokens), given=0 + ) 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( - "Your tembo.config/template specifies %s input tokens, you gave %s. Example command: %s", - len(self._all_input_tokens), - len(self.options.user_input), - self.options.example, - ) - else: - tembo.logger.critical( - "Your tembo.config/template specifies %s input tokens, you gave %s.", - len(self._all_input_tokens), - len(self.options.user_input), - ) - raise SystemExit(1) + raise exceptions.MismatchedTokenError( + expected=len(self._all_input_tokens), + given=len(self.options.user_input), + ) return def _substitute_tokens(self, tokenified_string: str) -> str: @@ -236,7 +217,7 @@ class Page(metaclass=ABCMeta): raise NotImplementedError @abstractmethod - def save_to_disk(self, dry_run: bool) -> None: + def save_to_disk(self) -> None: raise NotImplementedError @@ -261,7 +242,7 @@ class ScopedPage(Page): def __str__(self) -> str: return f"ScopedPage({self.path})" - def save_to_disk(self, dry_run: bool = False) -> None: + def save_to_disk(self) -> None: """Save the scoped page to disk and write the `page_content`. If the page already exists a message will be logged to stdout and no file @@ -279,16 +260,13 @@ class ScopedPage(Page): """ # TODO: move this functionality to the CLI so the page is created and the message # returned to the user from the CLI. - if dry_run: - tembo.logger.info("%s will be created", self.path) - raise SystemExit(0) # create the parent directories - scoped_note_file = pathlib.Path(self.path) - scoped_note_file.parents[0].mkdir(parents=True, exist_ok=True) - if scoped_note_file.exists(): + scoped_page_file = pathlib.Path(self.path) + scoped_page_file.parents[0].mkdir(parents=True, exist_ok=True) + if scoped_page_file.exists(): raise exceptions.ScopedPageAlreadyExists(f"{self.path} already exists") - with scoped_note_file.open("w", encoding="utf-8") as scoped_page: + with scoped_page_file.open("w", encoding="utf-8") as scoped_page: scoped_page.write(self.page_content) # TODO: pass this back somehow tembo.logger.info("Saved %s to disk", self.path) diff --git a/tests/test_journal/test_pages.py b/tests/test_journal/test_pages.py index 6a73852..7cf101a 100644 --- a/tests/test_journal/test_pages.py +++ b/tests/test_journal/test_pages.py @@ -272,6 +272,37 @@ def test_create_tokened_page_input_tokens_preserve_order(datadir, caplog): assert scoped_page_contents.readline() == "third_input second_input" +@pytest.mark.parametrize( + "user_input,expected,given", + [ + (None, 3, 0), + (("first_input", "second_input"), 3, 2), + (("first_input", "second_input", "third_input", "fourth_input"), 3, 4), + ], +) +def test_create_page_mismatched_tokens(tmpdir, user_input, expected, given): + # arrange + options = PageCreatorOptions( + base_path=str(tmpdir), + page_path="some_path", + filename="input_token_{input0}_{input1}_{input2}", + extension="md", + name="some_name", + user_input=user_input, + example=None, + template_filename=None, + template_path=None, + ) + + # act + with pytest.raises(exceptions.MismatchedTokenError) as mismatched_token_error: + scoped_page = ScopedPageCreator(options).create_page() + + # assert + assert mismatched_token_error.value.expected == expected + assert mismatched_token_error.value.given == given + + def test_create_page_spaces_in_path(tmpdir, caplog): # arrange options = PageCreatorOptions(