adding latest

This commit is contained in:
2021-11-09 22:46:45 +00:00
parent 78fdf54da3
commit c62d395df2
9 changed files with 125 additions and 120 deletions

View File

@@ -1,16 +1,19 @@
Priority:
Write the tests
Write the tests @done(21-11-07 15:36)
☐ test logs: <https://stackoverflow.com/questions/53125305/testing-logging-output-with-pytest>
document this
☐ Docstrings
☐ Update trilium with latest docstrings (documenting __init__ at class level etc)
Make sure the gist is updated for prospector with the right ignores
Documentation:
☐ documented poetry with extras (panaetius `pyproject.toml`)
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`
Document using `__main__.py` and `cli.py` @done(21-11-07 15:21)
Use Duty as an example
☐ Document regex usage
@@ -31,14 +34,14 @@ Documentation:
reading `.value.code`
reading `str(.value)`
Document working with exceptions
General pattern - raise exceptions in codebase, catch them in the CLI.
Document working with exceptions @done(21-11-09 22:17)
General pattern - raise exceptions in codebase, catch them in the CLI. @done(21-11-09 22:16)
Allows people to use via an API and handle the exceptions themselves.
You can use python builtins but custom exceptions are better for internal control
Capturing exceptions in the CLI.
Capturing exceptions in the CLI. @done(21-11-09 22:16)
Access the message of the exception with `.args[0]`.
use `raise SystemExit(1) from exception` in order to gracefully exit
Adding custom args to an exception
Adding custom args to an exception @done(21-11-09 22:17)
Overwrite `__init__`, access them in pytest with `.value.$args`
Access them in a try,except with `raise $excpetion as $name; $name.$arg`
@@ -60,13 +63,13 @@ Documentation:
<https://stackoverflow.com/questions/32234156/how-to-unimport-a-python-module-which-is-already-imported>
Functionality:
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? @done(21-11-09 22:17)
Define a format: [TEMBO:$datetime] $message 🐘 - document this in general python for CLI
Refactor the tembo new command so the cli is split out into manageable methods
Use the complicated CLI example so the tembo new has its own module to define functions in
Replace all logger errors with exceptions, move logger messages to the cli.
How to pass a successful save notification back to the CLI? Return a bool? Or is there some other way?
Replace pendulum with datetime
Refactor the tembo new command so the cli is split out into manageable methods @done(21-11-07 15:35)
Use the complicated CLI example so the tembo new has its own module to define functions in @cancelled(21-11-07 15:35)
Replace all logger errors with exceptions, move logger messages to the cli. @done(21-11-07 15:35)
How to pass a successful save notification back to the CLI? Return a bool? Or is there some other way? @done(21-11-07 15:35)
Replace pendulum with datetime @cancelled(21-11-07 15:35)
✔ Make options a property on the class, add to abstract @done(21-10-30 19:31)
☐ Use the python runner Duty
<https://github.com/pawamoy/duty>
@@ -78,8 +81,8 @@ Functionality:
Need to decide what file to place `__version__` in.
Logging:
Make all internal tembo logs be debug
User can enable them with the config
Make all internal tembo logs be debug @cancelled(21-11-09 22:20)
User can enable them with the config @cancelled(21-11-09 22:20)
VSCode:
PyInstaller:
@@ -92,7 +95,7 @@ VSCode:
walrus :=
Tests:
Write tests! @2d
Write tests! @2d @done(21-11-07 15:36)
Use coverage as going along to make sure all bases are covered in the testing
VSCode:

View File

@@ -0,0 +1,39 @@
Custom exceptions
Create an `./exceptions.py`.
Define any custom exceptions. Can append `Error` to the exception name if needed, otherwise be descriptive.
E.g `MismatchedTokenError`, `ScopedPageAlreadyExists`.
(If it would raise a `SystemExit(1)` use an Error).
Can set custom attributes on the Exception:
```
class MismatchedTokenError(Exception):
def __init__(self, expected: int, given: int) -> None:
self.expected = expected
self.given = given
super().__init__()
```
Can refer to these when capturing the exception:
```
except exceptions.MismatchedTokenError as exec_info:
click.echo(exec_info.expected, exec_info.given)
# error handling
```
Alternatively you can pass arbitrary `*args` into the exceptions and capture them with `args[0]`:
```
raise exceptions.TemplateNotFoundError("some message")
```
```
except exceptions.TemplateFileNotFoundError as exec_info:
cli_message(exec_info.args[0])
```

View File

@@ -1,39 +0,0 @@
# testing notes
## options
optional:
- user_input
- example
- template_filename
- template_path
required:
- base_path
- page_path
- filename
- extension
- name
## tests to write
- user input does not match number of input tokens
- no user input
- mismatched user input
- with/without example
- dry run
## tests done
- path/page filenames can contain spaces and they are converted
- user input is None
- page using/not using input tokens
- page using/not using date tokens
- page using/not using name tokens
- page with/without a template
- the given base path does not exist
- the given template file does not exist
- page already exists

90
poetry.lock generated
View File

@@ -25,7 +25,7 @@ tests = ["tox (>=2.6.0)", "pytest (>=3.0.3)", "pytest-cov (>=2.3.1)"]
name = "astroid"
version = "2.8.4"
description = "An abstract syntax tree for Python with inference support."
category = "dev"
category = "main"
optional = false
python-versions = "~=3.6"
@@ -38,7 +38,7 @@ wrapt = ">=1.11,<1.14"
name = "atomicwrites"
version = "1.4.0"
description = "Atomic file writes."
category = "main"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
@@ -46,7 +46,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
name = "attrs"
version = "21.2.0"
description = "Classes Without Boilerplate"
category = "main"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
@@ -60,7 +60,7 @@ tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>
name = "bandit"
version = "1.7.0"
description = "Security oriented static analyser for python code."
category = "dev"
category = "main"
optional = false
python-versions = ">=3.5"
@@ -105,7 +105,7 @@ toml = ["tomli"]
name = "dodgy"
version = "0.2.1"
description = "Dodgy: Searches for dodgy looking lines in Python code"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -137,7 +137,7 @@ ptyprocess = {version = ">=0.6,<1.0", markers = "sys_platform != \"win32\""}
name = "flake8"
version = "2.3.0"
description = "the modular source code checker: pep8, pyflakes and co"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -150,7 +150,7 @@ pyflakes = ">=0.8.1"
name = "flake8-polyfill"
version = "1.0.2"
description = "Polyfill package for Flake8 plugins"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -169,7 +169,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
name = "gitdb"
version = "4.0.9"
description = "Git Object Database"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.6"
@@ -180,7 +180,7 @@ smmap = ">=3.0.1,<6"
name = "gitpython"
version = "3.1.24"
description = "GitPython is a python library used to interact with Git repositories"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.7"
@@ -192,15 +192,15 @@ typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\"
name = "iniconfig"
version = "1.1.1"
description = "iniconfig: brain-dead simple config-ini parsing"
category = "main"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "isort"
version = "5.9.3"
version = "5.10.0"
description = "A Python utility / library to sort Python imports."
category = "dev"
category = "main"
optional = false
python-versions = ">=3.6.1,<4.0"
@@ -228,7 +228,7 @@ i18n = ["Babel (>=2.7)"]
name = "lazy-object-proxy"
version = "1.6.0"
description = "A fast and thorough lazy object proxy."
category = "dev"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
@@ -255,7 +255,7 @@ python-versions = ">=3.6"
name = "mccabe"
version = "0.6.1"
description = "McCabe checker, plugin for flake8"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -263,7 +263,7 @@ python-versions = "*"
name = "mypy"
version = "0.910"
description = "Optional static typing for Python"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.5"
@@ -280,7 +280,7 @@ python2 = ["typed-ast (>=1.4.0,<1.5.0)"]
name = "mypy-extensions"
version = "0.4.3"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -288,7 +288,7 @@ python-versions = "*"
name = "packaging"
version = "21.2"
description = "Core utilities for Python packages"
category = "main"
category = "dev"
optional = false
python-versions = ">=3.6"
@@ -316,7 +316,7 @@ url = "../panaetius"
name = "pbr"
version = "5.6.0"
description = "Python Build Reasonableness"
category = "dev"
category = "main"
optional = false
python-versions = ">=2.6"
@@ -347,7 +347,7 @@ pytzdata = ">=2020.1"
name = "pep8"
version = "1.7.1"
description = "Python style guide checker"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -355,7 +355,7 @@ python-versions = "*"
name = "pep8-naming"
version = "0.10.0"
description = "Check PEP-8 naming conventions, plugin for flake8"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -366,7 +366,7 @@ flake8-polyfill = ">=1.0.2,<2"
name = "platformdirs"
version = "2.4.0"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
category = "main"
optional = false
python-versions = ">=3.6"
@@ -378,7 +378,7 @@ test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock
name = "pluggy"
version = "1.0.0"
description = "plugin and hook calling mechanisms for python"
category = "main"
category = "dev"
optional = false
python-versions = ">=3.6"
@@ -390,7 +390,7 @@ testing = ["pytest", "pytest-benchmark"]
name = "prospector"
version = "1.5.1"
description = ""
category = "dev"
category = "main"
optional = false
python-versions = ">=3.6.1,<4.0"
@@ -433,7 +433,7 @@ python-versions = "*"
name = "py"
version = "1.10.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
category = "main"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
@@ -441,7 +441,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
name = "pycodestyle"
version = "2.8.0"
description = "Python style guide checker"
category = "dev"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
@@ -449,7 +449,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
name = "pydocstyle"
version = "6.1.1"
description = "Python docstring style checker"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.6"
@@ -463,7 +463,7 @@ toml = ["toml"]
name = "pyflakes"
version = "2.3.1"
description = "passive checker of Python programs"
category = "dev"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
@@ -498,7 +498,7 @@ python-versions = "*"
name = "pylint"
version = "2.11.1"
description = "python code static checker"
category = "dev"
category = "main"
optional = false
python-versions = "~=3.6"
@@ -515,7 +515,7 @@ typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""
name = "pylint-celery"
version = "0.3"
description = "pylint-celery is a Pylint plugin to aid Pylint in recognising and understandingerrors caused when using the Celery library"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -528,7 +528,7 @@ pylint-plugin-utils = ">=0.2.1"
name = "pylint-django"
version = "2.4.4"
description = "A Pylint plugin to help Pylint understand the Django web framework"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -544,7 +544,7 @@ with_django = ["django"]
name = "pylint-flask"
version = "0.6"
description = "pylint-flask is a Pylint plugin to aid Pylint in recognizing and understanding errors caused when using Flask"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -555,7 +555,7 @@ pylint-plugin-utils = ">=0.2.1"
name = "pylint-plugin-utils"
version = "0.6"
description = "Utilities and helpers for writing Pylint plugins"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -566,7 +566,7 @@ pylint = ">=1.7"
name = "pyparsing"
version = "2.4.7"
description = "Python parsing module"
category = "main"
category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
@@ -574,7 +574,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
name = "pytest"
version = "6.2.5"
description = "pytest: simple powerful testing with Python"
category = "main"
category = "dev"
optional = false
python-versions = ">=3.6"
@@ -595,7 +595,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm
name = "pytest-datadir"
version = "1.3.1"
description = "pytest plugin for test data directories and files"
category = "main"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
@@ -641,7 +641,7 @@ python-versions = ">=3.6"
name = "requirements-detector"
version = "0.7"
description = "Python tool to find and list requirements of a Python project"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -652,7 +652,7 @@ astroid = ">=1.4"
name = "setoptconf-tmp"
version = "0.3.1"
description = "A module for retrieving program settings from various sources in a consistant method."
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -671,7 +671,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
name = "smmap"
version = "5.0.0"
description = "A pure Python implementation of a sliding window memory map manager"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.6"
@@ -679,7 +679,7 @@ python-versions = ">=3.6"
name = "snowballstemmer"
version = "2.1.0"
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -687,7 +687,7 @@ python-versions = "*"
name = "stevedore"
version = "3.5.0"
description = "Manage dynamic plugins for Python applications"
category = "dev"
category = "main"
optional = false
python-versions = ">=3.6"
@@ -706,7 +706,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
name = "typing-extensions"
version = "3.10.0.2"
description = "Backported and Experimental Type Hints for Python 3.5+"
category = "dev"
category = "main"
optional = false
python-versions = "*"
@@ -714,14 +714,14 @@ python-versions = "*"
name = "wrapt"
version = "1.13.2"
description = "Module for decorators, wrappers and monkey patching."
category = "dev"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
content-hash = "a44f31719364047d4a223e74f8b31a8cb20ec7940bb82428e038648d70c71e0e"
content-hash = "f0d074e8db541f39e39949bd345cff134f8580756a39a25362680af14028071d"
[metadata.files]
altgraph = [
@@ -827,8 +827,8 @@ iniconfig = [
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
]
isort = [
{file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"},
{file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"},
{file = "isort-5.10.0-py3-none-any.whl", hash = "sha256:1a18ccace2ed8910bd9458b74a3ecbafd7b2f581301b0ab65cfdd4338272d76f"},
{file = "isort-5.10.0.tar.gz", hash = "sha256:e52ff6d38012b131628cf0f26c51e7bd3a7c81592eefe3ac71411e692f1b9345"},
]
jinja2 = [
{file = "Jinja2-3.0.2-py3-none-any.whl", hash = "sha256:8569982d3f0889eed11dd620c706d39b60c36d6d25843961f33f77fb6bc6b20c"},

View File

@@ -10,18 +10,19 @@ click = "^8.0.3"
pendulum = "^2.1.2"
Jinja2 = "^3.0.2"
panaetius = { path = "../panaetius", develop = true }
pytest-datadir = "^1.3.1"
[tool.poetry.dev-dependencies]
pytest = "^6.2.5"
prospector = { extras = ["with_bandit", "with_mypy"], version = "^1.5.1" }
pytest-datadir = "^1.3.1"
duty = "^0.7.0"
pyinstaller = "^4.5.1"
coverage = "^6.0.2"
isort = "^5.10.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
"tembo" = "tembo.cli.cli:run"
"tembo" = "tembo.cli.cli:main"

7
tembo/__main__.py Normal file
View File

@@ -0,0 +1,7 @@
import sys
from tembo.cli.cli import main
if __name__ == "__main__":
sys.exit(main())

View File

@@ -3,6 +3,7 @@ import os
import panaetius
from panaetius.exceptions import LoggingDirectoryDoesNotExistException
__version__ = "0.1.0"
if (config_path := os.environ.get("TEMBO_CONFIG")) is not None:

View File

@@ -6,10 +6,9 @@ from typing import Collection
import click
import tembo.cli
from tembo import exceptions
from tembo.journal import pages
from tembo.utils import Success
from tembo import exceptions
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
@@ -22,7 +21,7 @@ CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
prog_name="Tembo",
message=f"Tembo v{tembo.__version__} 🐘",
)
def run():
def main():
"""
Tembo - an organiser for work notes.
"""
@@ -82,7 +81,7 @@ def new(scope: str, inputs: Collection[str], dry_run: bool, example: bool):
_new_show_example(example, config_scope)
# if the name is in the config.yml, create the scoped page
scoped_page = new_create_scoped_page(config_scope, inputs)
scoped_page = _new_create_scoped_page(config_scope, inputs)
if dry_run:
cli_message(f"{scoped_page.path} will be created")
@@ -98,7 +97,7 @@ def new(scope: str, inputs: Collection[str], dry_run: bool, example: bool):
raise SystemExit(0) from scoped_page_already_exists
def new_create_scoped_page(config_scope: dict, inputs: Collection[str]) -> pages.Page:
def _new_create_scoped_page(config_scope: dict, inputs: Collection[str]) -> pages.Page:
page_creator_options = pages.PageCreatorOptions(
base_path=tembo.cli.CONFIG.base_path,
template_path=tembo.cli.CONFIG.template_path,
@@ -132,9 +131,7 @@ def new_create_scoped_page(config_scope: dict, inputs: Collection[str]) -> pages
def _new_verify_name_exists(scope: str) -> None:
_name_found = scope in [
user_scope["name"] for user_scope in tembo.cli.CONFIG.scopes
]
_name_found = scope in [user_scope["name"] for user_scope in tembo.cli.CONFIG.scopes]
if _name_found:
return
if len(tembo.cli.CONFIG.scopes) > 0:
@@ -145,9 +142,7 @@ def _new_verify_name_exists(scope: str) -> None:
raise exceptions.EmptyConfigYML(
f"Config.yml found in {tembo.cli.CONFIG.config_path} is empty"
)
raise exceptions.MissingConfigYML(
f"No config.yml found in {tembo.cli.CONFIG.config_path}"
)
raise exceptions.MissingConfigYML(f"No config.yml found in {tembo.cli.CONFIG.config_path}")
def _new_get_config_scope(scope: str) -> dict:
@@ -173,18 +168,14 @@ def _new_get_config_scope(scope: str) -> dict:
if key_error.args[0] in optional_keys:
config_scope.update({key_error.args[0]: None})
continue
raise exceptions.MandatoryKeyNotFound(
f"Key {key_error} not found in config.yml"
)
raise exceptions.MandatoryKeyNotFound(f"Key {key_error} not found in config.yml")
return config_scope
def _new_show_example(example: bool, config_scope: dict) -> None:
if example:
if isinstance(config_scope["example"], str):
cli_message(
f'Example for {config_scope["name"]}: {config_scope["example"]}'
)
cli_message(f'Example for {config_scope["name"]}: {config_scope["example"]}')
else:
cli_message("No example in config.yml")
raise SystemExit(0)
@@ -194,5 +185,5 @@ def cli_message(message: str) -> None:
click.echo(f"[TEMBO] {message} 🐘")
run.add_command(new)
run.add_command(list_all)
main.add_command(new)
main.add_command(list_all)

View File

@@ -1,3 +1,5 @@
"""Module that contains the factories to create Tembo pages."""
from __future__ import annotations
from abc import ABCMeta, abstractmethod