From 903755dd1e836cd8c40c13767efbf681ee284b43 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Fri, 22 Oct 2021 23:28:14 +0100 Subject: [PATCH] adding latest pages --- tembo/cli.py | 21 ++++-- tembo/exceptions.py | 4 + tembo/journal/pages.py | 167 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 166 insertions(+), 26 deletions(-) diff --git a/tembo/cli.py b/tembo/cli.py index 11e55ae..701ae72 100644 --- a/tembo/cli.py +++ b/tembo/cli.py @@ -32,13 +32,22 @@ def new(scope, inputs): Example: tembo new meeting my_presentation """ - for user_scope in tembo.CONFIG.scopes: - print(f"passed in scope: {scope}") - print(f'config scope: {user_scope["name"]}') - if user_scope["name"] == scope: - print(True) + # for user_scope in tembo.CONFIG.scopes: + # print(f"passed in scope: {scope}") + # print(f'config scope: {user_scope["name"]}') + # if user_scope["name"] == scope: + # print(True) - click.echo(inputs) + # 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) + + # click.echo(inputs) + # click.echo(type(inputs)) + + # if len(inputs) == 0, pass None is as user_input # TODO: decide on a date format to pass in diff --git a/tembo/exceptions.py b/tembo/exceptions.py index 07776a4..185cb68 100644 --- a/tembo/exceptions.py +++ b/tembo/exceptions.py @@ -3,3 +3,7 @@ class BasePathDoesNotExistError(Exception): pass + + +class MismatchingNumberOfInputTokensError(Exception): + pass diff --git a/tembo/journal/pages.py b/tembo/journal/pages.py index 9439b8e..8a796a1 100644 --- a/tembo/journal/pages.py +++ b/tembo/journal/pages.py @@ -2,24 +2,44 @@ from __future__ import annotations from abc import ABCMeta, abstractmethod import pathlib +import re -from tembo.exceptions import BasePathDoesNotExistError # noqa +import pendulum + +from tembo.exceptions import ( + BasePathDoesNotExistError, + MismatchingNumberOfInputTokensError, +) # noqa from tembo import logger class PageCreator: @abstractmethod - def create_page(self, base_path: str, page_path: str, user_input: str) -> Page: + def create_page( + self, + base_path: str, + page_path: str, + filename: str, + extension: str, + name: str, + user_input: tuple[str, ...], + ) -> Page: pass @staticmethod - def _convert_to_path(base_path: str, page_path: str) -> pathlib.Path: + def _convert_to_path( + base_path: str, page_path: str, filename: str, extension: str + ) -> pathlib.Path: if not pathlib.Path(base_path).expanduser().exists(): - logger.debug("base path of %s does not exist", base_path, exec_info=1) + logger.debug("base path of %s does not exist", base_path) raise BasePathDoesNotExistError( f"Your base path of {base_path} does not exist." ) - return pathlib.Path(base_path).expanduser() / pathlib.Path(page_path) + path_to_file = ( + pathlib.Path(base_path).expanduser() / pathlib.Path(page_path) / filename + ) + extension = extension[1:] if extension[0] == "." else extension + return path_to_file.with_suffix(f".{extension}") class ScopedPageCreator(PageCreator): @@ -27,16 +47,84 @@ class ScopedPageCreator(PageCreator): self.raw_entry_input = raw_entry_input def create_page( - self, base_path: str, page_path: str, user_input: str | None + self, + base_path: str, + page_path: str, + filename: str, + extension: str, + name: str, + user_input: tuple[str, ...] | None, ) -> Page: - path = self._convert_to_path(base_path, page_path) + path = self._convert_to_path(base_path, page_path, filename, extension) + 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 + def _substitute_tokens( + self, tokenified_string: str, user_input: tuple[str, ...] | None, name: str + ) -> str: + tokenified_string = self.__substitute_input_tokens( + tokenified_string, user_input + ) + tokenified_string = self.__substitute_name_tokens(tokenified_string, name) + tokenified_string = self.__substitute_date_tokens(tokenified_string) + return tokenified_string + + def __substitute_name_tokens( # noqa + self, 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 + ) -> str: + # find {inputN} tokens in string + input_extraction = re.findall(r"(\{input\d*\})", tokenified_string) + if user_input is None: + # if there's no user input, but the regex matches, raise error + if len(input_extraction) > 0: + raise MismatchingNumberOfInputTokensError( + f"Your config specifies {len(input_extraction)} input tokens, " + f"you gave 0", + ) + # 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): + 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 + 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 + # find any {d:DD-MM-YYYY} tokens + date_extraction_token = re.findall(r"(\{d\:[^}]*\})", tokenified_string) + for extracted_token in date_extraction_token: + # extract the inner DD-MM-YYYY only + strftime_value = re.match(r"\{d\:([^\}]*)\}", extracted_token) + if strftime_value: + strftime_value = strftime_value.group(1) + # replace {d:DD-MM-YYYY} with todays format of DD-MM-YYYY + tokenified_string = tokenified_string.replace( + extracted_token, pendulum.now().format(strftime_value) + ) + return tokenified_string + class Page(metaclass=ABCMeta): @abstractmethod - def __init__(self) -> None: + def __init__(self, path: pathlib.Path, page_content: str) -> None: pass @abstractmethod @@ -47,23 +135,62 @@ class Page(metaclass=ABCMeta): class ScopedPage(Page): """A Page that uses substitute tokens.""" - def __init__(self, path: str, raw_entry_input: dict): + def __init__(self, path: pathlib.Path, page_content: str): self.path = path - self._raw_entry_input = raw_entry_input - self._squashed_content: dict = {} - self._page_content: str = "" + self.page_content = page_content def save_to_disk(self) -> None: # create the file/folder if it doesnt exist pass - def _convert_to_path(self): - # take a path str and convert to pathlib - # substitute the tokens in - pass - def squash_raw_entry_input(self) -> None: - pass +if __name__ == "__main__": + c = ScopedPageCreator("") + # # raises error + # # print(c._substitute_tokens("scratchpad/{input0}-{d:DD-MM-YYYY}-{d:dddd}-{d:A}-file.md", None)) + # print( + # c._substitute_tokens( + # "scratchpad/{d:A}/{d:DD-MM-YYYY}-{d:dddd}-{d:A}-file-{input0}.md", ("last",) + # ) + # ) - def substitute_tokens(self) -> None: - pass + 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",), + ) + )