mirror of
https://github.com/dtomlinson91/tembo.git
synced 2025-12-22 04:05:45 +00:00
adding latest to cli
This commit is contained in:
@@ -3,13 +3,20 @@ Functionality:
|
||||
☐ 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.
|
||||
|
||||
VSCode:
|
||||
☐ Look at <https://github.com/CodeWithSwastik/vscode-ext>
|
||||
|
||||
Logging:
|
||||
☐ How to raise + debug an exception?
|
||||
☐ Document how to raise a logger.critical instead of exception
|
||||
in a try, except you can just do logger.critical(exec_info=1) to print the stack
|
||||
|
||||
Documentation:
|
||||
☐ Document usage of Panaetius in a module?
|
||||
☐ 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
|
||||
☐ Document latest typing.
|
||||
☐ Using from `__future__` with `|`
|
||||
☐ `using Tuple[str, ...]`
|
||||
☐ `Sequence` vs `Collection`
|
||||
☐ Document using jinja2 briefly and link to Tembo (link to <https://zetcode.com/python/jinja/>)
|
||||
|
||||
@@ -78,6 +78,8 @@ pep257:
|
||||
- D102
|
||||
# Missing docstring in public function
|
||||
- D103
|
||||
# Missing docstring in magic method
|
||||
- D105
|
||||
# One-line docstring should fit on one line with quotes
|
||||
- D200
|
||||
# No blank lines allowed after function docstring
|
||||
|
||||
36
tembo/cli.py
36
tembo/cli.py
@@ -1,6 +1,8 @@
|
||||
import click
|
||||
|
||||
import tembo
|
||||
from tembo.journal import pages
|
||||
|
||||
|
||||
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
||||
|
||||
@@ -32,27 +34,19 @@ 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)
|
||||
|
||||
# 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))
|
||||
|
||||
# if len(inputs) == 0, pass None is as user_input
|
||||
|
||||
|
||||
# TODO: decide on a date format to pass in
|
||||
@click.command(options_metavar="<options>")
|
||||
@click.option("--scope", "-s", help="The name of the scope in the Tembo config.yml.")
|
||||
@click.option("--date", "-d", help="")
|
||||
def archive(scope, date):
|
||||
print(f"{scope}, {date}")
|
||||
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()
|
||||
tembo.logger.info("Saved %s to disk", scoped_page)
|
||||
|
||||
|
||||
run.add_command(new)
|
||||
run.add_command(archive)
|
||||
|
||||
@@ -1,9 +1 @@
|
||||
"""Tembo exceptions."""
|
||||
|
||||
|
||||
class BasePathDoesNotExistError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MismatchingNumberOfInputTokensError(Exception):
|
||||
pass
|
||||
|
||||
@@ -7,10 +7,6 @@ import re
|
||||
import jinja2
|
||||
import pendulum
|
||||
|
||||
from tembo.exceptions import (
|
||||
BasePathDoesNotExistError,
|
||||
MismatchingNumberOfInputTokensError,
|
||||
) # noqa
|
||||
from tembo import logger, CONFIG
|
||||
|
||||
|
||||
@@ -24,7 +20,7 @@ class PageCreator:
|
||||
extension: str,
|
||||
name: str,
|
||||
user_input: tuple[str, ...],
|
||||
template_file: str | None = None,
|
||||
template_filename: str | None = None,
|
||||
) -> Page:
|
||||
pass
|
||||
|
||||
@@ -34,10 +30,8 @@ class PageCreator:
|
||||
) -> 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."
|
||||
)
|
||||
logger.critical("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()
|
||||
@@ -52,19 +46,19 @@ class PageCreator:
|
||||
# return path with a file
|
||||
return path_to_file.with_suffix(f".{extension}")
|
||||
|
||||
def _load_template(self, base_path: str, template_file: str) -> str:
|
||||
def _load_template(self, base_path: str, template_filename: 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)
|
||||
print(template_path, template_filename)
|
||||
# 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)
|
||||
loaded_template = env.get_template(template_filename)
|
||||
return loaded_template.render()
|
||||
|
||||
|
||||
@@ -83,7 +77,7 @@ class ScopedPageCreator(PageCreator):
|
||||
extension: str,
|
||||
name: str,
|
||||
user_input: tuple[str, ...] | None,
|
||||
template_file: str | None = None,
|
||||
template_filename: str | None = None,
|
||||
) -> Page:
|
||||
self.base_path = base_path
|
||||
self.page_path = page_path
|
||||
@@ -96,9 +90,9 @@ class ScopedPageCreator(PageCreator):
|
||||
# substitute tokens in the filepath
|
||||
path = pathlib.Path(self._substitute_tokens(str(path), user_input, name))
|
||||
# get the template file
|
||||
if template_file is not None:
|
||||
if template_filename is not None:
|
||||
# load the template file contents and substitute tokens
|
||||
template_contents = self._load_template(self.base_path, template_file)
|
||||
template_contents = self._load_template(self.base_path, template_filename)
|
||||
template_contents = self._substitute_tokens(
|
||||
template_contents, user_input, name
|
||||
)
|
||||
@@ -135,23 +129,26 @@ class ScopedPageCreator(PageCreator):
|
||||
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",
|
||||
logger.critical(
|
||||
"Your config/template specifies %s input tokens, you gave 0 "
|
||||
"- exiting",
|
||||
len(input_extraction),
|
||||
)
|
||||
# if there aren't any tokens in the string, return it
|
||||
raise SystemExit(1)
|
||||
# if there aren't any tokens in the string, return the string
|
||||
return tokenified_string
|
||||
# if there is user input, check the number of tokens matches what's passed in
|
||||
# if there is user input, check the number of tokens match what's passed in
|
||||
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)}",
|
||||
logger.critical(
|
||||
"Your config specifies %s input tokens, you gave %s - exiting",
|
||||
len(input_extraction),
|
||||
len(user_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
|
||||
raise SystemExit(1)
|
||||
# if the length of user input matches and number of tokens match, or there are
|
||||
# no 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
|
||||
@@ -165,7 +162,7 @@ class ScopedPageCreator(PageCreator):
|
||||
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
|
||||
# replace {d:DD-MM-YYYY} with todays date formatted as DD-MM-YYYY
|
||||
tokenified_string = tokenified_string.replace(
|
||||
extracted_token, pendulum.now().format(strftime_value)
|
||||
)
|
||||
@@ -189,6 +186,9 @@ class ScopedPage(Page):
|
||||
self.path = path
|
||||
self.page_content = page_content
|
||||
|
||||
def __str__(self):
|
||||
return f"ScopedPage({self.path})"
|
||||
|
||||
def save_to_disk(self) -> None:
|
||||
scoped_note_file = pathlib.Path(self.path)
|
||||
# create the parent directories
|
||||
@@ -197,6 +197,7 @@ 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)
|
||||
else:
|
||||
logger.info("The file %s already exists - skipping.", str(scoped_note_file))
|
||||
|
||||
|
||||
@@ -260,6 +261,7 @@ if __name__ == "__main__":
|
||||
("last",),
|
||||
"scratchpad.md.tpl",
|
||||
)
|
||||
print(test_page_with_template)
|
||||
test_page_with_template.save_to_disk()
|
||||
# print(
|
||||
# c.create_page(
|
||||
|
||||
Reference in New Issue
Block a user