mirror of
https://github.com/dtomlinson91/tembo.git
synced 2025-12-22 04:15:44 +00:00
adding latest working
This commit is contained in:
38
TODO.todo
38
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 <https://github.com/CodeWithSwastik/vscode-ext>
|
||||
@@ -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: <https://strftime.org>
|
||||
☐ 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)
|
||||
|
||||
79
tembo/cli.py
79
tembo/cli.py
@@ -14,6 +14,17 @@ def run():
|
||||
"""
|
||||
|
||||
|
||||
@click.command(options_metavar="<options>")
|
||||
def list_all():
|
||||
r"""List all names for "tembo new <name>"."""
|
||||
_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="<options>")
|
||||
@click.argument("scope", metavar="<scope>")
|
||||
@click.argument(
|
||||
@@ -22,9 +33,10 @@ def run():
|
||||
metavar="<inputs>",
|
||||
)
|
||||
@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.
|
||||
|
||||
<scope> 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"])
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user