From f91f83874d1c7b9f0d2b78f5b5e7f3f47723309a Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 25 Oct 2021 05:38:40 +0100 Subject: [PATCH] adding latest working --- TODO.todo | 38 ++++++++++++-------- tembo/cli.py | 79 +++++++++++++++++++++++++++++++++--------- tembo/journal/pages.py | 40 +++++++++++---------- 3 files changed, 107 insertions(+), 50 deletions(-) diff --git a/TODO.todo b/TODO.todo index 0f5c56b..0952f16 100644 --- a/TODO.todo +++ b/TODO.todo @@ -1,20 +1,18 @@ +Priority: + ☐ Go through code TODOs + ☐ Check code order and make sure things are where they should be + ☐ Document the python/logging/typing in Trilium + ☐ Write the tests + Functionality: - ☐ Handle case where there are no scopes in the config and command is invoked. - ☐ Have an `--example` flag to `new` that prints an example given in the `config.yml` - ☐ Should be a `tembo new --list` to list all possible names. - ☐ When template not found, raise a Tembo error - ☐ Convert spaces to underscores in filepath - currently raises jinja2.exceptions.TemplateNotFound on line 62, in _load_template - ☐ Add update notification? - check pypi for latest version and compare to current - ✔ `TEMBO_CONFIG` should follow same pattern as other env vars and be a python string when read in @done(21-10-24 05:31) + ☐ a Bug: - ☐ tokens - Say we have input0 and input3 in file path - and we have input1 and input2 in template - it only recognises this as 2 inputs total, not four. - passing in tembo new meeting a b will work and input0=input1, input3=input2 + ☐ a + +Tests: + ☐ Write tests! @2d + Use coverage as going along to make sure all bases are covered in the testing VSCode: ☐ Look at @@ -24,7 +22,6 @@ Logging: Documentation: ☐ Document usage of Panaetius in a module Using the logger, initialising with the config path etc - ✘ Uses Pendulum tokens: https://pendulum.eustace.io/docs/#tokens @cancelled(21-10-24 05:32) ☐ Uses `strftime` tokens: ☐ Document latest typing. ☐ Using from `__future__` with `|` @@ -48,3 +45,14 @@ Logging: ☐ Document how to overwrite these with ENV vars ☐ have a git repo with all the above already configured and walk user through clone the repo, delete .git, git init, configure and add git origin + +Archive: + ✔ tokens @done(21-10-25 05:35) @project(Bug) + ✔ Handle case where there are no scopes in the config and command is invoked. @done(21-10-25 04:32) @project(Functionality) + ✔ Have an `--example` flag to `new` that prints an example given in the `config.yml` @done(21-10-25 04:55) @project(Functionality) + ✔ Should be a `tembo new --list` to list all possible names. @done(21-10-25 05:28) @project(Functionality) + ✘ When template not found, raise a Tembo error @cancelled(21-10-25 05:29) @project(Functionality) + ✔ Convert spaces to underscores in filepath @done(21-10-25 05:35) @project(Functionality) + ✘ Add update notification? @cancelled(21-10-25 05:29) @project(Functionality) + ✔ `TEMBO_CONFIG` should follow same pattern as other env vars and be a python string when read in @done(21-10-24 05:31) @project(Functionality) + ✘ Uses Pendulum tokens: https://pendulum.eustace.io/docs/#tokens @cancelled(21-10-24 05:32) @project(Logging.Documentation) diff --git a/tembo/cli.py b/tembo/cli.py index e5810e6..1cc3de7 100644 --- a/tembo/cli.py +++ b/tembo/cli.py @@ -14,6 +14,17 @@ def run(): """ +@click.command(options_metavar="") +def list_all(): + r"""List all names for "tembo new ".""" + _all_scopes = [user_scope["name"] for user_scope in tembo.CONFIG.scopes] + tembo.logger.info( + "%s names found in config.yml: '%s'", len(_all_scopes), "', '".join(_all_scopes) + ) + raise SystemExit(0) + + +# TODO: organise this so all flags are at the top and in order @click.command(options_metavar="") @click.argument("scope", metavar="") @click.argument( @@ -22,9 +33,10 @@ def run(): metavar="", ) @click.option("--dry-run", is_flag=True, default=False) -def new(scope, inputs, dry_run): +@click.option("--example", is_flag=True, default=False) +def new(scope, inputs, dry_run, example): """ - Create a new note. + Create a new page. The name of the scope in the Tembo config.yml. @@ -32,21 +44,53 @@ def new(scope, inputs, dry_run): Example: tembo new meeting my_presentation """ - _name_found = scope in [user_scope["name"] for user_scope in tembo.CONFIG.scopes] + try: + _name_found = scope in [ + user_scope["name"] for user_scope in tembo.CONFIG.scopes + ] + except TypeError as type_error: + tembo.logger.critical("No scopes found in config.yml - exiting") + raise SystemExit(1) from type_error + + try: + config_scope = [ + ( + str(user_scope["name"]), + user_scope.get("example"), + str(user_scope["path"]), + str(user_scope["filename"]), + str(user_scope["extension"]), + user_scope.get("template_filename"), + ) + for user_scope in tembo.CONFIG.scopes + if user_scope["name"] == scope + ] + except KeyError as key_error: + tembo.logger.critical("Key %s not found in config.yml - exiting", key_error) + raise SystemExit(1) from key_error + + if example: + tembo.logger.info( + "Example for 'tembo new %s': %s", + config_scope[0][0], + config_scope[0][1] + if isinstance(config_scope[0][1], str) + else "No example in config.yml", + ) + raise SystemExit(0) + if _name_found: - for user_scope in tembo.CONFIG.scopes: - if user_scope["name"] == scope: - scoped_page = pages.ScopedPageCreator().create_page( - base_path=str(tembo.CONFIG.base_path), - page_path=str(user_scope["path"]), - filename=str(user_scope["filename"]), - extension=str(user_scope["extension"]), - name=str(user_scope["name"]), - user_input=inputs, - template_filename=str(user_scope["template_filename"]) - ) - scoped_page.save_to_disk(dry_run=dry_run) - raise SystemExit(0) + scoped_page = pages.ScopedPageCreator().create_page( + base_path=str(tembo.CONFIG.base_path), + page_path=config_scope[0][2], + filename=config_scope[0][3], + extension=config_scope[0][4], + name=config_scope[0][0], + user_input=inputs, + template_filename=config_scope[0][5], + ) + scoped_page.save_to_disk(dry_run=dry_run) + raise SystemExit(0) if not _name_found and len(tembo.CONFIG.scopes) > 0: tembo.logger.warning("Command %s not found in config.yml - exiting", scope) raise SystemExit(0) @@ -57,10 +101,11 @@ def new(scope, inputs, dry_run): run.add_command(new) +run.add_command(list_all) if __name__ == "__main__": # BUG: fix this bug where input tokens are mismatched # new(["meeting", "robs presentation", "meeting on gcp"]) - new(["meeting", "a", "b", "c", "d"]) + new(["meeting", "a", "b", "c", "d", "--example"]) # new(["meeting", "robs presentation"]) diff --git a/tembo/journal/pages.py b/tembo/journal/pages.py index 8609377..eeb42bc 100644 --- a/tembo/journal/pages.py +++ b/tembo/journal/pages.py @@ -8,7 +8,7 @@ from typing import Tuple import jinja2 import pendulum -from tembo import logger, CONFIG +import tembo class PageCreator: @@ -31,26 +31,30 @@ class PageCreator: ) -> pathlib.Path: # check if Tembo base path exists if not pathlib.Path(base_path).expanduser().exists(): - logger.critical("Tembo base path of %s does not exist - exiting", base_path) + tembo.logger.critical( + "Tembo base path of %s does not exist - exiting", base_path + ) raise SystemExit(1) path_to_file = ( pathlib.Path(base_path).expanduser() - / pathlib.Path(page_path).expanduser() - / filename + / pathlib.Path(page_path.replace(" ", "_")).expanduser() + / filename.replace(" ", "_") ) try: - # check for existing `.` in filename extension + # check for existing `.` in the extension extension = extension[1:] if extension[0] == "." else extension except IndexError: - # return paths without a file + # IndexError means the path is not a file, just a path return path_to_file # return path with a file return path_to_file.with_suffix(f".{extension}") def _load_template(self, base_path: str, template_filename: str) -> str: - if CONFIG.template_path is not None: + if tembo.CONFIG.template_path is not None: # check for overriden template_path - template_path = self._convert_to_path("", CONFIG.template_path, "", "") + template_path = self._convert_to_path( + "", tembo.CONFIG.template_path, "", "" + ) else: # default template_path is base_path / templates template_path = self._convert_to_path(base_path, ".templates", "", "") @@ -86,7 +90,7 @@ class ScopedPageCreator(PageCreator): self.extension = extension # verify the user input length matches the number of input tokens in the - # config/templates + # tembo.config/templates self._all_input_tokens = self._get_input_tokens(template_filename) self._verify_input_tokens(user_input) @@ -96,9 +100,7 @@ class ScopedPageCreator(PageCreator): ) # substitute tokens in the filepath - path = pathlib.Path( - self._substitute_tokens(str(path), user_input, name) - ) + path = pathlib.Path(self._substitute_tokens(str(path), user_input, name)) # get the template file if template_filename is not None: @@ -130,8 +132,8 @@ class ScopedPageCreator(PageCreator): def _verify_input_tokens(self, user_input: Tuple[str, ...] | Tuple[()]) -> None: if len(self._all_input_tokens) != len(user_input): - logger.critical( - "Your config/template specifies %s input tokens, you gave %s", + tembo.logger.critical( + "Your tembo.config/template specifies %s input tokens, you gave %s", len(self._all_input_tokens), len(user_input), ) @@ -161,7 +163,9 @@ class ScopedPageCreator(PageCreator): user_input: Tuple[str, ...] | Tuple[()], ) -> str: for input_value, extracted_token in zip(user_input, self._all_input_tokens): - tokenified_string = tokenified_string.replace(extracted_token, input_value) + tokenified_string = tokenified_string.replace( + extracted_token, input_value.replace(" ", "_") + ) return tokenified_string @staticmethod @@ -212,7 +216,7 @@ class ScopedPage(Page): def save_to_disk(self, dry_run: bool = False) -> None: if dry_run: - logger.info("%s will be created", self.path) + tembo.logger.info("%s will be created", self.path) raise SystemExit(0) # create the parent directories scoped_note_file = pathlib.Path(self.path) @@ -220,9 +224,9 @@ class ScopedPage(Page): if not scoped_note_file.exists(): with scoped_note_file.open("w", encoding="utf-8") as scoped_page: scoped_page.write(self.page_content) - logger.info("Saved %s to disk", self.path) + tembo.logger.info("Saved %s to disk", self.path) else: - logger.info("%s already exists - skipping.", self.path) + tembo.logger.info("%s already exists - skipping.", self.path) raise SystemExit(0)