mirror of
https://github.com/dtomlinson91/tembo.git
synced 2025-12-22 07:55:45 +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:
|
Functionality:
|
||||||
☐ Handle case where there are no scopes in the config and command is invoked.
|
☐ a
|
||||||
☐ 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)
|
|
||||||
|
|
||||||
Bug:
|
Bug:
|
||||||
☐ tokens
|
☐ a
|
||||||
Say we have input0 and input3 in file path
|
|
||||||
and we have input1 and input2 in template
|
Tests:
|
||||||
it only recognises this as 2 inputs total, not four.
|
☐ Write tests! @2d
|
||||||
passing in tembo new meeting a b will work and input0=input1, input3=input2
|
Use coverage as going along to make sure all bases are covered in the testing
|
||||||
|
|
||||||
VSCode:
|
VSCode:
|
||||||
☐ Look at <https://github.com/CodeWithSwastik/vscode-ext>
|
☐ Look at <https://github.com/CodeWithSwastik/vscode-ext>
|
||||||
@@ -24,7 +22,6 @@ Logging:
|
|||||||
Documentation:
|
Documentation:
|
||||||
☐ Document usage of Panaetius in a module
|
☐ Document usage of Panaetius in a module
|
||||||
Using the logger, initialising with the config path etc
|
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>
|
☐ Uses `strftime` tokens: <https://strftime.org>
|
||||||
☐ Document latest typing.
|
☐ Document latest typing.
|
||||||
☐ Using from `__future__` with `|`
|
☐ Using from `__future__` with `|`
|
||||||
@@ -48,3 +45,14 @@ Logging:
|
|||||||
☐ Document how to overwrite these with ENV vars
|
☐ Document how to overwrite these with ENV vars
|
||||||
☐ have a git repo with all the above already configured and walk user through
|
☐ 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
|
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)
|
||||||
|
|||||||
67
tembo/cli.py
67
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.command(options_metavar="<options>")
|
||||||
@click.argument("scope", metavar="<scope>")
|
@click.argument("scope", metavar="<scope>")
|
||||||
@click.argument(
|
@click.argument(
|
||||||
@@ -22,9 +33,10 @@ def run():
|
|||||||
metavar="<inputs>",
|
metavar="<inputs>",
|
||||||
)
|
)
|
||||||
@click.option("--dry-run", is_flag=True, default=False)
|
@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.
|
<scope> The name of the scope in the Tembo config.yml.
|
||||||
|
|
||||||
@@ -32,18 +44,50 @@ def new(scope, inputs, dry_run):
|
|||||||
|
|
||||||
Example: tembo new meeting my_presentation
|
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:
|
if _name_found:
|
||||||
for user_scope in tembo.CONFIG.scopes:
|
|
||||||
if user_scope["name"] == scope:
|
|
||||||
scoped_page = pages.ScopedPageCreator().create_page(
|
scoped_page = pages.ScopedPageCreator().create_page(
|
||||||
base_path=str(tembo.CONFIG.base_path),
|
base_path=str(tembo.CONFIG.base_path),
|
||||||
page_path=str(user_scope["path"]),
|
page_path=config_scope[0][2],
|
||||||
filename=str(user_scope["filename"]),
|
filename=config_scope[0][3],
|
||||||
extension=str(user_scope["extension"]),
|
extension=config_scope[0][4],
|
||||||
name=str(user_scope["name"]),
|
name=config_scope[0][0],
|
||||||
user_input=inputs,
|
user_input=inputs,
|
||||||
template_filename=str(user_scope["template_filename"])
|
template_filename=config_scope[0][5],
|
||||||
)
|
)
|
||||||
scoped_page.save_to_disk(dry_run=dry_run)
|
scoped_page.save_to_disk(dry_run=dry_run)
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
@@ -57,10 +101,11 @@ def new(scope, inputs, dry_run):
|
|||||||
|
|
||||||
|
|
||||||
run.add_command(new)
|
run.add_command(new)
|
||||||
|
run.add_command(list_all)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# BUG: fix this bug where input tokens are mismatched
|
# BUG: fix this bug where input tokens are mismatched
|
||||||
# new(["meeting", "robs presentation", "meeting on gcp"])
|
# new(["meeting", "robs presentation", "meeting on gcp"])
|
||||||
new(["meeting", "a", "b", "c", "d"])
|
new(["meeting", "a", "b", "c", "d", "--example"])
|
||||||
# new(["meeting", "robs presentation"])
|
# new(["meeting", "robs presentation"])
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from typing import Tuple
|
|||||||
import jinja2
|
import jinja2
|
||||||
import pendulum
|
import pendulum
|
||||||
|
|
||||||
from tembo import logger, CONFIG
|
import tembo
|
||||||
|
|
||||||
|
|
||||||
class PageCreator:
|
class PageCreator:
|
||||||
@@ -31,26 +31,30 @@ class PageCreator:
|
|||||||
) -> pathlib.Path:
|
) -> pathlib.Path:
|
||||||
# check if Tembo base path exists
|
# check if Tembo base path exists
|
||||||
if not pathlib.Path(base_path).expanduser().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)
|
raise SystemExit(1)
|
||||||
path_to_file = (
|
path_to_file = (
|
||||||
pathlib.Path(base_path).expanduser()
|
pathlib.Path(base_path).expanduser()
|
||||||
/ pathlib.Path(page_path).expanduser()
|
/ pathlib.Path(page_path.replace(" ", "_")).expanduser()
|
||||||
/ filename
|
/ filename.replace(" ", "_")
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
# check for existing `.` in filename extension
|
# check for existing `.` in the extension
|
||||||
extension = extension[1:] if extension[0] == "." else extension
|
extension = extension[1:] if extension[0] == "." else extension
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# return paths without a file
|
# IndexError means the path is not a file, just a path
|
||||||
return path_to_file
|
return path_to_file
|
||||||
# return path with a file
|
# return path with a file
|
||||||
return path_to_file.with_suffix(f".{extension}")
|
return path_to_file.with_suffix(f".{extension}")
|
||||||
|
|
||||||
def _load_template(self, base_path: str, template_filename: str) -> str:
|
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
|
# 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:
|
else:
|
||||||
# default template_path is base_path / templates
|
# default template_path is base_path / templates
|
||||||
template_path = self._convert_to_path(base_path, ".templates", "", "")
|
template_path = self._convert_to_path(base_path, ".templates", "", "")
|
||||||
@@ -86,7 +90,7 @@ class ScopedPageCreator(PageCreator):
|
|||||||
self.extension = extension
|
self.extension = extension
|
||||||
|
|
||||||
# verify the user input length matches the number of input tokens in the
|
# 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._all_input_tokens = self._get_input_tokens(template_filename)
|
||||||
self._verify_input_tokens(user_input)
|
self._verify_input_tokens(user_input)
|
||||||
|
|
||||||
@@ -96,9 +100,7 @@ class ScopedPageCreator(PageCreator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# substitute tokens in the filepath
|
# substitute tokens in the filepath
|
||||||
path = pathlib.Path(
|
path = pathlib.Path(self._substitute_tokens(str(path), user_input, name))
|
||||||
self._substitute_tokens(str(path), user_input, name)
|
|
||||||
)
|
|
||||||
|
|
||||||
# get the template file
|
# get the template file
|
||||||
if template_filename is not None:
|
if template_filename is not None:
|
||||||
@@ -130,8 +132,8 @@ class ScopedPageCreator(PageCreator):
|
|||||||
|
|
||||||
def _verify_input_tokens(self, user_input: Tuple[str, ...] | Tuple[()]) -> None:
|
def _verify_input_tokens(self, user_input: Tuple[str, ...] | Tuple[()]) -> None:
|
||||||
if len(self._all_input_tokens) != len(user_input):
|
if len(self._all_input_tokens) != len(user_input):
|
||||||
logger.critical(
|
tembo.logger.critical(
|
||||||
"Your config/template specifies %s input tokens, you gave %s",
|
"Your tembo.config/template specifies %s input tokens, you gave %s",
|
||||||
len(self._all_input_tokens),
|
len(self._all_input_tokens),
|
||||||
len(user_input),
|
len(user_input),
|
||||||
)
|
)
|
||||||
@@ -161,7 +163,9 @@ class ScopedPageCreator(PageCreator):
|
|||||||
user_input: Tuple[str, ...] | Tuple[()],
|
user_input: Tuple[str, ...] | Tuple[()],
|
||||||
) -> str:
|
) -> str:
|
||||||
for input_value, extracted_token in zip(user_input, self._all_input_tokens):
|
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
|
return tokenified_string
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -212,7 +216,7 @@ class ScopedPage(Page):
|
|||||||
|
|
||||||
def save_to_disk(self, dry_run: bool = False) -> None:
|
def save_to_disk(self, dry_run: bool = False) -> None:
|
||||||
if dry_run:
|
if dry_run:
|
||||||
logger.info("%s will be created", self.path)
|
tembo.logger.info("%s will be created", self.path)
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
# create the parent directories
|
# create the parent directories
|
||||||
scoped_note_file = pathlib.Path(self.path)
|
scoped_note_file = pathlib.Path(self.path)
|
||||||
@@ -220,9 +224,9 @@ class ScopedPage(Page):
|
|||||||
if not scoped_note_file.exists():
|
if not scoped_note_file.exists():
|
||||||
with scoped_note_file.open("w", encoding="utf-8") as scoped_page:
|
with scoped_note_file.open("w", encoding="utf-8") as scoped_page:
|
||||||
scoped_page.write(self.page_content)
|
scoped_page.write(self.page_content)
|
||||||
logger.info("Saved %s to disk", self.path)
|
tembo.logger.info("Saved %s to disk", self.path)
|
||||||
else:
|
else:
|
||||||
logger.info("%s already exists - skipping.", self.path)
|
tembo.logger.info("%s already exists - skipping.", self.path)
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user