diff --git a/TODO.todo b/TODO.todo index 8b543aa..efe3316 100644 --- a/TODO.todo +++ b/TODO.todo @@ -1,7 +1,4 @@ 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 ☐ test logs: document this @@ -28,15 +25,8 @@ Documentation: ☐ Can prospector ignore tests dir? document this in the gist if so 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) - ☐ Make user_input optional @important ☐ 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. @done(21-10-30 02:14) - ☐ Replace scoped page creator inputs so that the whole class uses the options dict rather than the variables passed around. + ☐ Make options a property on the class, add to abstract ☐ Use the python runner Duty ☐ Run tests @@ -75,6 +65,17 @@ Logging: clone the repo, delete .git, git init, configure and add git origin 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) ✔ 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) diff --git a/tembo/journal/pages.py b/tembo/journal/pages.py index 8562d9d..a305d36 100644 --- a/tembo/journal/pages.py +++ b/tembo/journal/pages.py @@ -42,28 +42,32 @@ class PageCreatorOptions: class PageCreator: + def __init__(self, options: PageCreatorOptions) -> None: + raise NotImplementedError + @abstractmethod def create_page(self, options: PageCreatorOptions) -> Page: raise NotImplementedError - @staticmethod - def _convert_to_path( - base_path: str, page_path: str, filename: str, extension: str - ) -> pathlib.Path: + def _convert_to_path(self) -> pathlib.Path: # 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 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) path_to_file = ( - pathlib.Path(base_path).expanduser() - / pathlib.Path(page_path.replace(" ", "_")).expanduser() - / filename.replace(" ", "_") + pathlib.Path(self.options.base_path).expanduser() + / pathlib.Path(self.options.page_path.replace(" ", "_")).expanduser() + / self.options.filename.replace(" ", "_") ) try: # 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: # IndexError means the path is not a file, just a path return path_to_file @@ -107,20 +111,14 @@ class ScopedPageCreator(PageCreator): """ def __init__(self) -> None: - # self.base_path = "" - # self.page_path = "" - # self.filename = "" - # self.extension = "" self._all_input_tokens: list[str] = [] self.options: PageCreatorOptions def create_page(self, options: PageCreatorOptions) -> Page: self.options = options - self._all_input_tokens = self._get_input_tokens( - options.template_filename, options.template_path - ) - self._verify_input_tokens(options.user_input, options.example) + self._all_input_tokens = self._get_input_tokens() + self._verify_input_tokens() path = self._convert_to_path( self.options.base_path, @@ -128,34 +126,26 @@ class ScopedPageCreator(PageCreator): self.options.filename, self.options.extension, ) - path = pathlib.Path( - self._substitute_tokens(str(path), options.user_input, options.name) - ) + path = pathlib.Path(self._substitute_tokens(str(path))) - template_contents = self._get_template_contents( - options.template_filename, options.template_path - ) + template_contents = self._get_template_contents() if options.template_filename is not None: - template_contents = self._substitute_tokens( - template_contents, options.user_input, options.name - ) + template_contents = self._substitute_tokens(template_contents) return ScopedPage(path, template_contents) - def _get_template_contents( - self, template_filename: str | None, template_path: str | None - ) -> str: + def _get_template_contents(self) -> str: return ( self._load_template( - self.options.base_path, template_filename, template_path + self.options.base_path, + self.options.template_filename, + self.options.template_path, ) - if template_filename is not None + if self.options.template_filename is not None else "" ) - def _get_input_tokens( - self, template_filename: str | None, template_path: str | None - ) -> list[str]: + def _get_input_tokens(self) -> list[str]: path = str( pathlib.Path( self.options.base_path, @@ -164,24 +154,20 @@ class ScopedPageCreator(PageCreator): self.options.extension, ).expanduser() ) - template_contents = self._get_template_contents( - template_filename, template_path - ) + template_contents = self._get_template_contents() # get the input tokens from both the path and the template all_input_tokens = [] for tokenified_string in (path, template_contents): all_input_tokens.extend(re.findall(r"(\{input\d*\})", tokenified_string)) return sorted(all_input_tokens) - def _verify_input_tokens( - self, user_input: Collection[str] | None, example: str | None - ) -> None: - if len(self._all_input_tokens) > 0 and user_input is None: - if example is not None: + 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), - example, + self.options.example, ) else: tembo.logger.critical( @@ -189,58 +175,50 @@ class ScopedPageCreator(PageCreator): len(self._all_input_tokens), ) raise SystemExit(1) - if user_input is None: + if self.options.user_input is None: return - if len(self._all_input_tokens) != len(user_input): - if example is not None: + 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(user_input), - example, + 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(user_input), + len(self.options.user_input), ) raise SystemExit(1) return - def _substitute_tokens( - self, - tokenified_string: str, - user_input: Collection[str] | None, - name: str, - ) -> str: + def _substitute_tokens(self, tokenified_string: str) -> str: """For a tokened string, substitute input, name and date tokens.""" - tokenified_string = self.__substitute_input_tokens( - tokenified_string, user_input - ) - tokenified_string = self.__substitute_name_tokens(tokenified_string, name) + tokenified_string = self.__substitute_input_tokens(tokenified_string) + tokenified_string = self.__substitute_name_tokens(tokenified_string) tokenified_string = self.__substitute_date_tokens(tokenified_string) return tokenified_string - def __substitute_input_tokens( - self, - tokenified_string: str, - user_input: Collection[str] | None, - ) -> str: - if user_input is not None: - for input_value, extracted_token in zip(user_input, self._all_input_tokens): + def __substitute_input_tokens(self, tokenified_string: str) -> str: + if self.options.user_input is not None: + for input_value, extracted_token in zip( + self.options.user_input, self._all_input_tokens + ): tokenified_string = tokenified_string.replace( extracted_token, input_value.replace(" ", "_") ) return tokenified_string - @staticmethod - def __substitute_name_tokens(tokenified_string: str, name: str) -> str: + def __substitute_name_tokens(self, tokenified_string: str) -> str: """Find any `{name}` tokens and substitute for the name value.""" name_extraction = re.findall(r"(\{name\})", tokenified_string) 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 @staticmethod