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
|
☐ Write the tests
|
||||||
☐ test logs: <https://stackoverflow.com/questions/53125305/testing-logging-output-with-pytest>
|
☐ test logs: <https://stackoverflow.com/questions/53125305/testing-logging-output-with-pytest>
|
||||||
document this
|
document this
|
||||||
☐
|
|
||||||
☐ Docstrings
|
☐ Docstrings
|
||||||
|
|
||||||
Documentation:
|
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`
|
☐ Write documentation using `mkdocs`
|
||||||
☐ Look at how to use github actions
|
☐ Look at how to use github actions
|
||||||
Use <https://github.com/pdm-project/pdm/tree/main/.github/workflows> for an example
|
Use <https://github.com/pdm-project/pdm/tree/main/.github/workflows> for an example
|
||||||
☐ Build the docs using a github action.
|
☐ Build the docs using a github action.
|
||||||
|
|
||||||
Functionality:
|
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?
|
☐ 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>
|
<https://github.com/pawamoy/duty>
|
||||||
☐ Run tests
|
☐ Run tests
|
||||||
☐ Update poetry
|
☐ Update poetry
|
||||||
☐ Build docs
|
☐ Build docs
|
||||||
☐ Document using Duty
|
☐ 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:
|
Tests:
|
||||||
☐ Write tests! @2d
|
☐ Write tests! @2d
|
||||||
Use coverage as going along to make sure all bases are covered in the testing
|
Use coverage as going along to make sure all bases are covered in the testing
|
||||||
@@ -33,8 +50,6 @@ VSCode:
|
|||||||
Logging:
|
Logging:
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
☐ a
|
|
||||||
|
|
||||||
Tembo:
|
Tembo:
|
||||||
☐ Document creating new Tembo config
|
☐ Document creating new Tembo config
|
||||||
☐ ~/tembo needs creating
|
☐ ~/tembo needs creating
|
||||||
|
|||||||
55
tembo/cli.py
55
tembo/cli.py
@@ -1,9 +1,10 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
import tembo
|
import tembo
|
||||||
from tembo.journal import pages
|
from tembo.journal import pages
|
||||||
|
|
||||||
|
|
||||||
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
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
|
# get the scope information from the tembo config.yml
|
||||||
try:
|
try:
|
||||||
config_scope = [
|
config_scope = {
|
||||||
(
|
option: str(user_scope[option])
|
||||||
str(user_scope["name"]),
|
for option in [
|
||||||
user_scope.get("example"),
|
"name",
|
||||||
str(user_scope["path"]),
|
"example",
|
||||||
str(user_scope["filename"]),
|
"path",
|
||||||
str(user_scope["extension"]),
|
"filename",
|
||||||
user_scope.get("template_filename"),
|
"extension",
|
||||||
)
|
"template_filename",
|
||||||
|
]
|
||||||
for user_scope in tembo.CONFIG.scopes
|
for user_scope in tembo.CONFIG.scopes
|
||||||
if user_scope["name"] == scope
|
if user_scope["name"] == scope
|
||||||
]
|
}
|
||||||
except KeyError as key_error:
|
except KeyError as key_error:
|
||||||
# raise error if any non optional keys are missing
|
# raise error if any non optional keys are missing
|
||||||
tembo.logger.critical("Key %s not found in config.yml - exiting", key_error)
|
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:
|
if example:
|
||||||
tembo.logger.info(
|
tembo.logger.info(
|
||||||
"Example for 'tembo new %s': %s",
|
"Example for 'tembo new %s': %s",
|
||||||
config_scope[0][0],
|
config_scope["name"],
|
||||||
config_scope[0][1]
|
config_scope["example"]
|
||||||
if isinstance(config_scope[0][1], str)
|
if isinstance(config_scope[0][1], str)
|
||||||
else "No example in config.yml",
|
else "No example in config.yml",
|
||||||
)
|
)
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
|
|
||||||
# if the name is in the config.yml, create the scoped page
|
# if the name is in the config.yml, create the scoped page
|
||||||
|
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["template_filename"],
|
||||||
|
template_path=tembo.CONFIG.template_path,
|
||||||
|
)
|
||||||
if _name_found:
|
if _name_found:
|
||||||
scoped_page = pages.ScopedPageCreator().create_page(
|
scoped_page = pages.ScopedPageCreator().create_page(page_creator_options)
|
||||||
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)
|
scoped_page.save_to_disk(dry_run=dry_run)
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
if not _name_found and len(tembo.CONFIG.scopes) > 0:
|
if not _name_found and len(tembo.CONFIG.scopes) > 0:
|
||||||
@@ -121,5 +125,10 @@ run.add_command(list_all)
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# new(["meeting", "robs presentation", "meeting on gcp"])
|
# new(["meeting", "robs presentation", "meeting on gcp"])
|
||||||
new(["meeting", "a", "b", "c", "d", "--example"])
|
new(["meeting", "a", "b", "c", "d"])
|
||||||
# new(["meeting", "robs presentation"])
|
# 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 __future__ import annotations
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
from dataclasses import dataclass
|
||||||
import pathlib
|
import pathlib
|
||||||
import re
|
import re
|
||||||
from typing import Collection
|
from typing import Collection
|
||||||
@@ -12,18 +13,21 @@ import pendulum
|
|||||||
import tembo
|
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:
|
class PageCreator:
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def create_page(
|
def create_page(self, options: PageCreatorOptions) -> Page:
|
||||||
self,
|
|
||||||
base_path: str,
|
|
||||||
page_path: str,
|
|
||||||
filename: str,
|
|
||||||
extension: str,
|
|
||||||
name: str,
|
|
||||||
user_input: Collection[str],
|
|
||||||
template_filename: str | None = None,
|
|
||||||
) -> Page:
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -50,17 +54,19 @@ class PageCreator:
|
|||||||
# 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, template_path: str | None
|
||||||
|
) -> str:
|
||||||
# check for overriden template_path
|
# check for overriden template_path
|
||||||
if tembo.CONFIG.template_path is not None:
|
if template_path is not None:
|
||||||
template_path = self._convert_to_path(
|
converted_template_path = self._convert_to_path("", template_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", "", "")
|
converted_template_path = self._convert_to_path(
|
||||||
|
base_path, ".templates", "", ""
|
||||||
|
)
|
||||||
# load the template folder
|
# 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)
|
env = jinja2.Environment(loader=file_loader, autoescape=True)
|
||||||
# load the template contents
|
# load the template contents
|
||||||
try:
|
try:
|
||||||
@@ -91,25 +97,18 @@ class ScopedPageCreator(PageCreator):
|
|||||||
self.extension = ""
|
self.extension = ""
|
||||||
self._all_input_tokens: list[str] = []
|
self._all_input_tokens: list[str] = []
|
||||||
|
|
||||||
def create_page(
|
def create_page(self, options: PageCreatorOptions) -> Page:
|
||||||
self,
|
self.base_path = options.base_path
|
||||||
base_path: str,
|
self.page_path = options.page_path
|
||||||
page_path: str,
|
self.filename = options.filename
|
||||||
filename: str,
|
self.extension = options.extension
|
||||||
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
|
|
||||||
|
|
||||||
# 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
|
||||||
# tembo config/templates
|
# tembo config/templates
|
||||||
self._all_input_tokens = self._get_input_tokens(template_filename)
|
self._all_input_tokens = self._get_input_tokens(
|
||||||
self._verify_input_tokens(user_input)
|
options.template_filename, options.template_path
|
||||||
|
)
|
||||||
|
self._verify_input_tokens(options.user_input)
|
||||||
|
|
||||||
# get the path of the scoped page
|
# get the path of the scoped page
|
||||||
path = self._convert_to_path(
|
path = self._convert_to_path(
|
||||||
@@ -117,24 +116,32 @@ class ScopedPageCreator(PageCreator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# substitute tokens in the filepath
|
# 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
|
# 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
|
# 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 = self._substitute_tokens(
|
||||||
template_contents, user_input, name
|
template_contents, options.user_input, options.name
|
||||||
)
|
)
|
||||||
return ScopedPage(path, template_contents)
|
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(
|
path = str(
|
||||||
pathlib.Path(
|
pathlib.Path(
|
||||||
self.base_path, self.page_path, self.filename, self.extension
|
self.base_path, self.page_path, self.filename, self.extension
|
||||||
).expanduser()
|
).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
|
# get the input tokens from both the path and the template
|
||||||
all_input_tokens = []
|
all_input_tokens = []
|
||||||
for tokenified_string in (path, template_contents):
|
for tokenified_string in (path, template_contents):
|
||||||
@@ -150,9 +157,11 @@ class ScopedPageCreator(PageCreator):
|
|||||||
)
|
)
|
||||||
raise SystemExit(1)
|
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 (
|
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
|
if template_filename is not None
|
||||||
else ""
|
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