From 36d489e7289c3b99b1ad2bacc91c0a8e6e5a4dde Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 23 Oct 2021 01:47:51 +0100 Subject: [PATCH] updating TODO --- TODO.todo | 4 + tembo/__init__.py | 1 + tembo/cli.py | 6 +- tembo/journal/pages.py | 198 ++++++++++++++++++++++++++++------------- 4 files changed, 144 insertions(+), 65 deletions(-) diff --git a/TODO.todo b/TODO.todo index eb0e90a..4b64cd6 100644 --- a/TODO.todo +++ b/TODO.todo @@ -9,3 +9,7 @@ Logging: Documentation: ☐ Document usage of Panaetius in a module? ☐ Uses Pendulum tokens: https://pendulum.eustace.io/docs/#tokens + ☐ Document latest typing. + ☐ Using from `__future__` with `|` + ☐ `using Tuple[str, ...]` + ☐ `Sequence` vs `Collection` diff --git a/tembo/__init__.py b/tembo/__init__.py index 0425bbc..5e73856 100644 --- a/tembo/__init__.py +++ b/tembo/__init__.py @@ -9,6 +9,7 @@ else: panaetius.set_config(CONFIG, "base_path", "~/tembo") +panaetius.set_config(CONFIG, "template_path", "~/tembo/templates") panaetius.set_config(CONFIG, "scopes", {}) panaetius.set_config(CONFIG, "logging.level", "DEBUG") panaetius.set_config(CONFIG, "logging.path") diff --git a/tembo/cli.py b/tembo/cli.py index 701ae72..4053e4c 100644 --- a/tembo/cli.py +++ b/tembo/cli.py @@ -38,11 +38,7 @@ def new(scope, inputs): # if user_scope["name"] == scope: # print(True) - # TODO: write check for if titles is missing - from panaetius.utilities import Squash - - for user_scope in tembo.CONFIG.scopes: - print(Squash({"titles": user_scope["titles"]}).as_dict) + # TODO: if user_scope["template"], check for a template in the templates dir. If it doesn't exist raise MissingTemplateError # click.echo(inputs) # click.echo(type(inputs)) diff --git a/tembo/journal/pages.py b/tembo/journal/pages.py index 8a796a1..7abb124 100644 --- a/tembo/journal/pages.py +++ b/tembo/journal/pages.py @@ -4,13 +4,14 @@ from abc import ABCMeta, abstractmethod import pathlib import re +import jinja2 import pendulum from tembo.exceptions import ( BasePathDoesNotExistError, MismatchingNumberOfInputTokensError, ) # noqa -from tembo import logger +from tembo import logger, CONFIG class PageCreator: @@ -23,6 +24,7 @@ class PageCreator: extension: str, name: str, user_input: tuple[str, ...], + template_file: str | None = None, ) -> Page: pass @@ -30,21 +32,48 @@ class PageCreator: def _convert_to_path( base_path: str, page_path: str, filename: str, extension: str ) -> pathlib.Path: + # check if Tembo base path exists if not pathlib.Path(base_path).expanduser().exists(): logger.debug("base path of %s does not exist", base_path) raise BasePathDoesNotExistError( f"Your base path of {base_path} does not exist." ) path_to_file = ( - pathlib.Path(base_path).expanduser() / pathlib.Path(page_path) / filename + pathlib.Path(base_path).expanduser() + / pathlib.Path(page_path).expanduser() + / filename ) - extension = extension[1:] if extension[0] == "." else extension + try: + # check for existing `.` in filename extension + extension = extension[1:] if extension[0] == "." else extension + except IndexError: + # return paths without a file + 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_file: str) -> str: + if CONFIG.template_path is not None: + # check for overriden template_path + template_path = self._convert_to_path("", CONFIG.template_path, "", "") + else: + # default template_path is base_path / templates + template_path = self._convert_to_path(base_path, "templates", "", "") + print(template_path, template_file) + # load the template folder + file_loader = jinja2.FileSystemLoader(template_path) + env = jinja2.Environment(loader=file_loader, autoescape=True) + # load the template contents + loaded_template = env.get_template(template_file) + return loaded_template.render() + class ScopedPageCreator(PageCreator): - def __init__(self, raw_entry_input: str) -> None: - self.raw_entry_input = raw_entry_input + def __init__(self) -> None: + self.base_path = "" + self.page_path = "" + self.filename = "" + self.extension = "" def create_page( self, @@ -54,17 +83,34 @@ class ScopedPageCreator(PageCreator): extension: str, name: str, user_input: tuple[str, ...] | None, + template_file: str | None = None, ) -> Page: - path = self._convert_to_path(base_path, page_path, filename, extension) + self.base_path = base_path + self.page_path = page_path + self.filename = filename + self.extension = extension + # get the path of the scoped page + path = self._convert_to_path( + self.base_path, self.page_path, self.filename, self.extension + ) + # substitute tokens in the filepath path = pathlib.Path(self._substitute_tokens(str(path), user_input, name)) - return path - # return ScopedPage(path, "") - # substitute tokens in path - # substitute tokens in raw_entry_input + # get the template file + if template_file is not None: + # load the template file contents and substitute tokens + template_contents = self._load_template(self.base_path, template_file) + template_contents = self._substitute_tokens( + template_contents, user_input, name + ) + # print(template_contents) + else: + template_contents = "" + return ScopedPage(path, template_contents) def _substitute_tokens( self, tokenified_string: str, user_input: tuple[str, ...] | None, name: str ) -> str: + # for a tokened string, substitute input, name and date tokens tokenified_string = self.__substitute_input_tokens( tokenified_string, user_input ) @@ -72,17 +118,17 @@ class ScopedPageCreator(PageCreator): tokenified_string = self.__substitute_date_tokens(tokenified_string) return tokenified_string - def __substitute_name_tokens( # noqa - self, tokenified_string: str, name: str - ) -> str: + @staticmethod + def __substitute_name_tokens(tokenified_string: str, name: str) -> str: # find any {name} tokens and substitute for the name value name_extraction = re.findall(r"(\{name\d*\})", tokenified_string) for extracted_input in name_extraction: tokenified_string = tokenified_string.replace(extracted_input, name) return tokenified_string - def __substitute_input_tokens( # noqa - self, tokenified_string: str, user_input: tuple[str, ...] | None + @staticmethod + def __substitute_input_tokens( + tokenified_string: str, user_input: tuple[str, ...] | None ) -> str: # find {inputN} tokens in string input_extraction = re.findall(r"(\{input\d*\})", tokenified_string) @@ -96,18 +142,22 @@ class ScopedPageCreator(PageCreator): # if there aren't any tokens in the string, return it return tokenified_string # if there is user input, check the number of tokens matches what's passed in - if len(input_extraction) != len(user_input): + if len(input_extraction) != len(user_input) and len(input_extraction) > 0: + # if there are input matches and they don't equal the number of input + # tokens, raise error logger.debug("MismatchingNumberOfInputTokensError") raise MismatchingNumberOfInputTokensError( f"Your config specifies {len(input_extraction)} input tokens, " f"you gave {len(user_input)}", ) - # substitute each token with the user's input + # if the length of both matches and tokens match, or there arent any input + # matches, then substitute each token with the user's input for extracted_input, input_value in zip(input_extraction, user_input): tokenified_string = tokenified_string.replace(extracted_input, input_value) return tokenified_string - def __substitute_date_tokens(self, tokenified_string: str) -> str: # noqa + @staticmethod + def __substitute_date_tokens(tokenified_string: str) -> str: # find any {d:DD-MM-YYYY} tokens date_extraction_token = re.findall(r"(\{d\:[^}]*\})", tokenified_string) for extracted_token in date_extraction_token: @@ -140,12 +190,18 @@ class ScopedPage(Page): self.page_content = page_content def save_to_disk(self) -> None: - # create the file/folder if it doesnt exist - pass + scoped_note_file = pathlib.Path(self.path) + # create the parent directories + scoped_note_file.parents[0].mkdir(parents=True, exist_ok=True) + + 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("The file %s already exists - skipping.", str(scoped_note_file)) if __name__ == "__main__": - c = ScopedPageCreator("") + c = ScopedPageCreator() # # raises error # # print(c._substitute_tokens("scratchpad/{input0}-{d:DD-MM-YYYY}-{d:dddd}-{d:A}-file.md", None)) # print( @@ -154,43 +210,65 @@ if __name__ == "__main__": # ) # ) - print( - c.create_page( - "~/tembo", - "{name}", - "{input0}-{input1}-file", - "md", - "scratchpad", - ("first", "second"), - ) - ) - print( - c.create_page( - "~/tembo", - "{name}/{d:MMMM-YY}", - "{input0}-{d:DD-MM-YYYY}-{d:dddd}-{d:A}-file", - "md", - "scratchpad", - ("first",), - ) - ) - print( - c.create_page( - "~/tembo", - "{name}/{d:DD-MM-YYYY}-{d:dddd}-{d:A}", - "file", - "md", - "scratchpad", - None, - ) - ) - print( - c.create_page( - "~/tembo", - "{name}/{d:A}/{d:DD-MM-YYYY}-{d:dddd}-{d:A}", - "file-{input0}-{name}", - ".md", - "meeting", - ("last",), - ) + # print( + # c.create_page( + # "~/tembo", + # "{name}", + # "{input0}-{input1}-file", + # "md", + # "scratchpad", + # ("first", "second"), + # ) + # ) + # print( + # c.create_page( + # "~/tembo", + # "{name}/{d:MMMM-YY}", + # "{input0}-{d:DD-MM-YYYY}-{d:dddd}-{d:A}-file", + # "md", + # "scratchpad", + # ("first",), + # ) + # ) + # print( + # c.create_page( + # "~/tembo", + # "{name}/{d:DD-MM-YYYY}-{d:dddd}-{d:A}", + # "file", + # "md", + # "scratchpad", + # None, + # ) + # ) + # print( + # c.create_page( + # "~/tembo", + # "{name}/{d:A}/{d:DD-MM-YYYY}-{d:dddd}-{d:A}", + # "file-{input0}-{name}", + # ".md", + # "meeting", + # ("last",), + # "scratchpad.md.tpl", + # ) + # ) + test_page_with_template = c.create_page( + "~/tembo", + "{name}/{d:A}/{d:DD-MM-YYYY}-{d:dddd}-{d:A}", + "file-{input0}-{name}", + ".md", + "meeting", + ("last",), + "scratchpad.md.tpl", ) + test_page_with_template.save_to_disk() + # print( + # c.create_page( + # "~/tembo", + # "{name}/{d:A}/{d:DD-MM-YYYY}-{d:dddd}-{d:A}", + # "file-{input0}-{name}", + # ".md", + # "meeting", + # ("last",), + # "scratchpad_templates/scratchpad.md.tpl", + # ) + # )