mirror of
https://github.com/dtomlinson91/tembo.git
synced 2025-12-22 06:15:45 +00:00
adding options class and tidying up
This commit is contained in:
23
TODO.todo
23
TODO.todo
@@ -5,24 +5,41 @@ Priority:
|
||||
☐ Write the tests
|
||||
☐ test logs: <https://stackoverflow.com/questions/53125305/testing-logging-output-with-pytest>
|
||||
document this
|
||||
☐
|
||||
☐ Docstrings
|
||||
|
||||
Documentation:
|
||||
Docstrings:
|
||||
☐ Use Duty to write module docstrings
|
||||
☐ Use Duty to add Class docstrings
|
||||
☐ Document these in Trilium and rewrite the docstrings notes
|
||||
☐ Add the comment on Reddit (artie buco?) about imports in a module
|
||||
☐ Document using `__main__.py` and `cli.py`
|
||||
Use Duty as an example
|
||||
|
||||
☐ Write documentation using `mkdocs`
|
||||
☐ Look at how to use github actions
|
||||
Use <https://github.com/pdm-project/pdm/tree/main/.github/workflows> for an example
|
||||
☐ Build the docs using a github action.
|
||||
|
||||
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)
|
||||
☐ Add the `--example` output to the miscounted token message so the user knows the correct command to use.
|
||||
✔ Page options dataclass @done(21-10-28 20:09)
|
||||
☐ Replace loggers with `click.echo` for command outputs. Keep logging messages for actual logging messages?
|
||||
☐ Use the python runner
|
||||
☐ Use the python runner Duty
|
||||
<https://github.com/pawamoy/duty>
|
||||
☐ Run tests
|
||||
☐ Update poetry
|
||||
☐ Build docs
|
||||
☐ Document using Duty
|
||||
|
||||
VSCode:
|
||||
PyInstaller:
|
||||
☐ Document build error: <https://github.com/pyenv/pyenv/issues/1095>
|
||||
PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.8.11
|
||||
☐ Freeze a click app: <https://stackoverflow.com/questions/45090083/freeze-a-program-created-with-pythons-click-pacage>
|
||||
|
||||
Tests:
|
||||
☐ Write tests! @2d
|
||||
Use coverage as going along to make sure all bases are covered in the testing
|
||||
@@ -33,8 +50,6 @@ VSCode:
|
||||
Logging:
|
||||
|
||||
Documentation:
|
||||
☐ a
|
||||
|
||||
Tembo:
|
||||
☐ Document creating new Tembo config
|
||||
☐ ~/tembo needs creating
|
||||
|
||||
53
tembo/cli.py
53
tembo/cli.py
@@ -1,9 +1,10 @@
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
import tembo
|
||||
from tembo.journal import pages
|
||||
|
||||
|
||||
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
||||
|
||||
|
||||
@@ -62,18 +63,19 @@ def new(scope, inputs, dry_run, example):
|
||||
|
||||
# get the scope information from the tembo config.yml
|
||||
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"),
|
||||
)
|
||||
config_scope = {
|
||||
option: str(user_scope[option])
|
||||
for option in [
|
||||
"name",
|
||||
"example",
|
||||
"path",
|
||||
"filename",
|
||||
"extension",
|
||||
"template_filename",
|
||||
]
|
||||
for user_scope in tembo.CONFIG.scopes
|
||||
if user_scope["name"] == scope
|
||||
]
|
||||
}
|
||||
except KeyError as key_error:
|
||||
# raise error if any non optional keys are missing
|
||||
tembo.logger.critical("Key %s not found in config.yml - exiting", key_error)
|
||||
@@ -83,24 +85,26 @@ def new(scope, inputs, dry_run, example):
|
||||
if example:
|
||||
tembo.logger.info(
|
||||
"Example for 'tembo new %s': %s",
|
||||
config_scope[0][0],
|
||||
config_scope[0][1]
|
||||
config_scope["name"],
|
||||
config_scope["example"]
|
||||
if isinstance(config_scope[0][1], str)
|
||||
else "No example in config.yml",
|
||||
)
|
||||
raise SystemExit(0)
|
||||
|
||||
# if the name is in the config.yml, create the scoped page
|
||||
if _name_found:
|
||||
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],
|
||||
page_creator_options = pages.PageCreatorOptions(
|
||||
base_path=tembo.CONFIG.base_path,
|
||||
page_path=config_scope["path"],
|
||||
filename=config_scope["filename"],
|
||||
extension=config_scope["extension"],
|
||||
name=config_scope["name"],
|
||||
user_input=inputs,
|
||||
template_filename=config_scope[0][5],
|
||||
template_filename=config_scope["template_filename"],
|
||||
template_path=tembo.CONFIG.template_path,
|
||||
)
|
||||
if _name_found:
|
||||
scoped_page = pages.ScopedPageCreator().create_page(page_creator_options)
|
||||
scoped_page.save_to_disk(dry_run=dry_run)
|
||||
raise SystemExit(0)
|
||||
if not _name_found and len(tembo.CONFIG.scopes) > 0:
|
||||
@@ -121,5 +125,10 @@ run.add_command(list_all)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# new(["meeting", "robs presentation", "meeting on gcp"])
|
||||
new(["meeting", "a", "b", "c", "d", "--example"])
|
||||
new(["meeting", "a", "b", "c", "d"])
|
||||
# new(["meeting", "robs presentation"])
|
||||
|
||||
# pyinstaller
|
||||
# if getattr(sys, "frozen", False):
|
||||
# run(sys.argv[1:])
|
||||
# run(sys.argv[1:])
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
import pathlib
|
||||
import re
|
||||
from typing import Collection
|
||||
@@ -12,18 +13,21 @@ import pendulum
|
||||
import tembo
|
||||
|
||||
|
||||
@dataclass
|
||||
class PageCreatorOptions:
|
||||
base_path: str
|
||||
page_path: str
|
||||
filename: str
|
||||
extension: str
|
||||
name: str
|
||||
user_input: Collection[str]
|
||||
template_filename: str | None = None
|
||||
template_path: str | None = None
|
||||
|
||||
|
||||
class PageCreator:
|
||||
@abstractmethod
|
||||
def create_page(
|
||||
self,
|
||||
base_path: str,
|
||||
page_path: str,
|
||||
filename: str,
|
||||
extension: str,
|
||||
name: str,
|
||||
user_input: Collection[str],
|
||||
template_filename: str | None = None,
|
||||
) -> Page:
|
||||
def create_page(self, options: PageCreatorOptions) -> Page:
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
@@ -50,17 +54,19 @@ class PageCreator:
|
||||
# return path with a file
|
||||
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, template_path: str | None
|
||||
) -> str:
|
||||
# check for overriden template_path
|
||||
if tembo.CONFIG.template_path is not None:
|
||||
template_path = self._convert_to_path(
|
||||
"", tembo.CONFIG.template_path, "", ""
|
||||
)
|
||||
if template_path is not None:
|
||||
converted_template_path = self._convert_to_path("", template_path, "", "")
|
||||
else:
|
||||
# default template_path is base_path / .templates
|
||||
template_path = self._convert_to_path(base_path, ".templates", "", "")
|
||||
converted_template_path = self._convert_to_path(
|
||||
base_path, ".templates", "", ""
|
||||
)
|
||||
# load the template folder
|
||||
file_loader = jinja2.FileSystemLoader(template_path)
|
||||
file_loader = jinja2.FileSystemLoader(converted_template_path)
|
||||
env = jinja2.Environment(loader=file_loader, autoescape=True)
|
||||
# load the template contents
|
||||
try:
|
||||
@@ -91,25 +97,18 @@ class ScopedPageCreator(PageCreator):
|
||||
self.extension = ""
|
||||
self._all_input_tokens: list[str] = []
|
||||
|
||||
def create_page(
|
||||
self,
|
||||
base_path: str,
|
||||
page_path: str,
|
||||
filename: str,
|
||||
extension: str,
|
||||
name: str,
|
||||
user_input: Collection[str],
|
||||
template_filename: str | None = None,
|
||||
) -> Page:
|
||||
self.base_path = base_path
|
||||
self.page_path = page_path
|
||||
self.filename = filename
|
||||
self.extension = extension
|
||||
def create_page(self, options: PageCreatorOptions) -> Page:
|
||||
self.base_path = options.base_path
|
||||
self.page_path = options.page_path
|
||||
self.filename = options.filename
|
||||
self.extension = options.extension
|
||||
|
||||
# verify the user input length matches the number of input tokens in the
|
||||
# tembo config/templates
|
||||
self._all_input_tokens = self._get_input_tokens(template_filename)
|
||||
self._verify_input_tokens(user_input)
|
||||
self._all_input_tokens = self._get_input_tokens(
|
||||
options.template_filename, options.template_path
|
||||
)
|
||||
self._verify_input_tokens(options.user_input)
|
||||
|
||||
# get the path of the scoped page
|
||||
path = self._convert_to_path(
|
||||
@@ -117,24 +116,32 @@ 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), options.user_input, options.name)
|
||||
)
|
||||
|
||||
# get the template file
|
||||
template_contents = self._get_template_contents(template_filename)
|
||||
template_contents = self._get_template_contents(
|
||||
options.template_filename, options.template_path
|
||||
)
|
||||
# substitute tokens in template_contents
|
||||
if template_filename is not None:
|
||||
if options.template_filename is not None:
|
||||
template_contents = self._substitute_tokens(
|
||||
template_contents, user_input, name
|
||||
template_contents, options.user_input, options.name
|
||||
)
|
||||
return ScopedPage(path, template_contents)
|
||||
|
||||
def _get_input_tokens(self, template_filename: str | None) -> list[str]:
|
||||
def _get_input_tokens(
|
||||
self, template_filename: str | None, template_path: str | None
|
||||
) -> list[str]:
|
||||
path = str(
|
||||
pathlib.Path(
|
||||
self.base_path, self.page_path, self.filename, self.extension
|
||||
).expanduser()
|
||||
)
|
||||
template_contents = self._get_template_contents(template_filename)
|
||||
template_contents = self._get_template_contents(
|
||||
template_filename, template_path
|
||||
)
|
||||
# get the input tokens from both the path and the template
|
||||
all_input_tokens = []
|
||||
for tokenified_string in (path, template_contents):
|
||||
@@ -150,9 +157,11 @@ class ScopedPageCreator(PageCreator):
|
||||
)
|
||||
raise SystemExit(1)
|
||||
|
||||
def _get_template_contents(self, template_filename: str | None) -> str:
|
||||
def _get_template_contents(
|
||||
self, template_filename: str | None, template_path: str | None
|
||||
) -> str:
|
||||
return (
|
||||
self._load_template(self.base_path, template_filename)
|
||||
self._load_template(self.base_path, template_filename, template_path)
|
||||
if template_filename is not None
|
||||
else ""
|
||||
)
|
||||
|
||||
0
tests/test_journal/test_pages.py
Normal file
0
tests/test_journal/test_pages.py
Normal file
Reference in New Issue
Block a user