From d3ad87211e6d180796762be427d81fea91dd7abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?c=C4=83t=C4=83lin?= Date: Sat, 1 Apr 2023 12:37:10 +0200 Subject: [PATCH] feat: move project from poetry to pdm, rewrite from scratch and add basic `notebooks`, `edit` and `show` commands --- .drone.yml | 99 ----- .gitignore | 3 + .pre-commit-config.yaml | 56 +-- Makefile | 16 + README.md | 17 +- halig/__init__.py | 3 + halig/app.py | 0 halig/commands/__init__.py | 0 halig/commands/base.py | 23 ++ halig/commands/edit.py | 75 ++++ halig/commands/notebooks.py | 31 ++ halig/commands/show.py | 34 ++ halig/config.py | 83 ----- halig/edit_note.py | 29 -- halig/encryption.py | 34 ++ halig/exceptions.py | 75 ---- halig/logger.py | 27 -- halig/main.py | 90 ++--- halig/new_note.py | 42 --- halig/settings.py | 37 ++ halig/utils.py | 48 --- noxfile.py | 16 + pdm.lock | 722 ++++++++++++++++++++++++++++++++++++ poetry.lock | 596 ----------------------------- pyproject.toml | 90 +++-- sample.env | 5 + tests/commands/__init__.py | 0 tests/conftest.py | 98 +++++ tests/file_fixtures.py | 21 -- tests/test_config.py | 70 ---- tests/test_edit.py | 79 ---- tests/test_encryption.py | 54 +++ tests/test_new_note.py | 95 ----- tests/test_settings.py | 42 +++ tests/test_utils.py | 33 -- 35 files changed, 1309 insertions(+), 1434 deletions(-) delete mode 100644 .drone.yml create mode 100644 Makefile create mode 100644 halig/app.py create mode 100644 halig/commands/__init__.py create mode 100644 halig/commands/base.py create mode 100644 halig/commands/edit.py create mode 100644 halig/commands/notebooks.py create mode 100644 halig/commands/show.py delete mode 100644 halig/config.py delete mode 100644 halig/edit_note.py create mode 100644 halig/encryption.py delete mode 100644 halig/exceptions.py delete mode 100644 halig/logger.py mode change 100755 => 100644 halig/main.py delete mode 100644 halig/new_note.py create mode 100644 halig/settings.py delete mode 100644 halig/utils.py create mode 100644 noxfile.py create mode 100644 pdm.lock delete mode 100644 poetry.lock create mode 100644 sample.env create mode 100644 tests/commands/__init__.py create mode 100644 tests/conftest.py delete mode 100644 tests/file_fixtures.py delete mode 100644 tests/test_config.py delete mode 100644 tests/test_edit.py create mode 100644 tests/test_encryption.py delete mode 100644 tests/test_new_note.py create mode 100644 tests/test_settings.py delete mode 100644 tests/test_utils.py diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 8ef110c..0000000 --- a/.drone.yml +++ /dev/null @@ -1,99 +0,0 @@ ---- -kind: pipeline -type: docker -name: build and test - -trigger: - ref: - - refs/heads/** - - refs/tags/v* -environment: - REGISTRY_HOST: https://git.roboces.dev - DESTINATION_PREFIX: git.roboces.dev/catalin/halig - PRE_COMMIT_HOME: /drone/src/.cache/.pre-commit - -steps: - - name: restore_cache - image: meltwater/drone-cache - pull: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: AWS_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY: - from_secret: AWS_SECRET_ACCESS_KEY - settings: - restore: true - bucket: halig-cache - endpoint: https://s3.fukurokuju.dev - region: us-east-1 - path_style: true - mount: - - .venv - - .cache/.pre-commit - - - name: install_deps - pull: true - image: git.roboces.dev/catalin/poetry:beta - commands: - - poetry config virtualenvs.in-project 1 - - poetry install --with linters,test - depends_on: - - restore_cache - - - name: lint - pull: true - image: git.roboces.dev/catalin/poetry:beta - commands: - - .venv/bin/pre-commit run --all-files --color always - depends_on: - - install_deps - - - name: tests - pull: true - image: git.roboces.dev/catalin/poetry:beta - commands: - - apk add --no-cache age openssh - - ssh-keygen -t ed25519 -C "" -N "" -f /root/.ssh/id_ed25519 - - .venv/bin/pytest - depends_on: - - install_deps - - - name: deploy - pull: true - image: git.roboces.dev/catalin/poetry:beta - commands: - - poetry build - - poetry config repositories.roboces https://git.roboces.dev/api/packages/catalin/pypi - - poetry config http-basic.roboces "$REGISTRY_USERNAME" "$REGISTRY_PASSWORD" - - poetry publish --repository roboces - when: - ref: - - refs/tags/v* - depends_on: - - lint - - tests - - - name: rebuild cache - image: meltwater/drone-cache - pull: true - environment: - AWS_ACCESS_KEY_ID: - from_secret: AWS_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY: - from_secret: AWS_SECRET_ACCESS_KEY - settings: - rebuild: true - path_style: true - bucket: halig-cache - endpoint: https://s3.fukurokuju.dev - region: us-east-1 - mount: - - .venv - - .cache/.pre-commit - when: - status: - - failure - - success - depends_on: - - lint - - tests diff --git a/.gitignore b/.gitignore index f87107a..63a5179 100644 --- a/.gitignore +++ b/.gitignore @@ -212,3 +212,6 @@ dmypy.json # Cython debug symbols cython_debug/ report.xml +.pdm-python +reportlog.json +.ruff_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index de22862..a0449a3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,11 @@ default_language_version: python: python3.10 +files: ^halig|tests$ + repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: trailing-whitespace args: [ --markdown-linebreak-ext=md ] @@ -18,52 +20,34 @@ repos: - id: debug-statements - id: mixed-line-ending args: [ --fix=lf ] - - id: detect-private-key - - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.9.0 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.260 hooks: - - id: python-check-blanket-noqa - - id: python-use-type-annotations + - id: ruff + args: + - --fix + - --exit-non-zero-on-fix - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 23.3.0 hooks: - id: black pass_filenames: false args: - "halig" - - repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 + - repo: local hooks: - - id: flake8 - name: flake8 except __init__.py - exclude: /__init__\.py$ - additional_dependencies: [ "flake8-bugbear==19.8.0" ] - - id: flake8 - name: flake8 only __init__.py - args: [ "--extend-ignore=F401" ] # ignore unused imports in __init__.py - files: /__init__\.py$ - additional_dependencies: [ "flake8-bugbear==19.8.0" ] - - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v0.961' - hooks: - id: mypy - files: ^halig/ - additional_dependencies: - - types-deprecated==1.2.8 - - types-pyyaml==6.0.11 + name: mypy + entry: pdm run mypy + language: system + types: [ python ] - - repo: https://github.com/asottile/pyupgrade - rev: v2.34.0 - hooks: - - id: pyupgrade - - - repo: https://github.com/PyCQA/bandit - rev: 1.7.4 - hooks: - - id: bandit - files: ^darkroot/ - args: [ -r ] + - id: pyright + name: pyright + entry: pdm run pyright + language: system + types: [ python ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..078df8c --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ + +linters: + pre-commit run --all-files --color always + +.PHONY: tests +tests: + pdm run pytest --cov=halig -vv tests --report-log reportlog.json + pdm run coverage html + pdm run coverage xml + +.PHONY: dist +dist: + pdm build + +publish: + pdm publish -u $(ROBOCES_REGISTRY_USERNAME) -P $(ROBOCES_REGISTRY_PASSWORD) -r https://git.roboces.dev/api/packages/catalin/pypi diff --git a/README.md b/README.md index 7cf57d0..93dbcdf 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,23 @@ # halig -[![Build Status](https://qa.roboces.dev/api/badges/catalin/halig/status.svg?ref=refs/heads/main)](https://qa.roboces.dev/catalin/halig) +[(r)age](https://github.com/woodruffw/pyrage) encrypted note-taking CLI app + +## install and init + +You can use plain `pip` but I'd recommend `pipx` + +```shell +pipx install halig +``` + +## cli mode ```shell -$ halig init # create and write $HOME/.config/halig/halig.yml $ halig edit some_notebook # edit today's note $ halig edit some_notebook/foo # edit /path/to/some_notebook/foo.age $ halig notebooks # list current notebooks ``` + +## tui mode + +wip \ No newline at end of file diff --git a/halig/__init__.py b/halig/__init__.py index e69de29..b0e7b86 100644 --- a/halig/__init__.py +++ b/halig/__init__.py @@ -0,0 +1,3 @@ +from typer import Typer + +app = Typer() diff --git a/halig/app.py b/halig/app.py new file mode 100644 index 0000000..e69de29 diff --git a/halig/commands/__init__.py b/halig/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/halig/commands/base.py b/halig/commands/base.py new file mode 100644 index 0000000..9dadd00 --- /dev/null +++ b/halig/commands/base.py @@ -0,0 +1,23 @@ +from abc import ABC, abstractmethod + +import pendulum +from pendulum.datetime import DateTime +from pendulum.tz import local_timezone + +from halig.settings import Settings + + +class ICommand(ABC): + @abstractmethod + def run(self): + ... + + +class BaseCommand(ICommand): + @property + def today(self) -> DateTime: + tz = local_timezone() + return pendulum.now(tz) + + def __init__(self, settings: Settings, *args, **kwargs): + self.settings = settings diff --git a/halig/commands/edit.py b/halig/commands/edit.py new file mode 100644 index 0000000..38ae2ac --- /dev/null +++ b/halig/commands/edit.py @@ -0,0 +1,75 @@ +import os +import subprocess +import tempfile +from pathlib import Path + +from halig.commands.base import BaseCommand +from halig.encryption import Encryptor +from halig.settings import Settings + + +class EditCommand(BaseCommand): + """*The* edit command, which also encompasses creating a new file when needed, + that is, when `note_path` is a folder, a new YYYY-MM-DD.age file will be created + if it does not exist and filled with an encrypted empty string + + Attributes: + note_path (Path): The path to a specific .age note or a notebook. + Note that the input note_path will be modified in order to append it + to the notebooks root path defined by `Settings.notebooks_root_path` + attribute. This means that the input path is relative to the mentioned + root path + settings (Settings): Settings object + encryptor (Encryptor): Encryptor object + """ + + def __init__(self, note_path: Path, settings: Settings): + super().__init__(settings) + + self.note_path = self.settings.notebooks_root_path / note_path + self.encryptor = Encryptor(self.settings) + + if self.note_path.is_dir(): + self.note_path /= f"{self.today.date()}.age" + + if not self.note_path.name.endswith(".age"): + err = f"File {self.note_path.name} is not a valid AGE file" + raise ValueError(err) + + if not self.note_path.exists(): + empty_encrypted = self.encryptor.encrypt("") + with self.note_path.open("wb") as f: + f.write(empty_encrypted) + + def edit_contents(self, original_contents: bytes) -> bytes: + """Let the user edit the contents by opening an in-memory tempfile + using $EDITOR and encrypting the new contents + + Args: + original_contents (bytes): original data that will be dumped into the + tempfile for the user to modify + Returns: + modified data as bytes + """ + + with tempfile.NamedTemporaryFile(delete=False, suffix=".md") as tf: + tf.write(original_contents) + temp_path = Path(tf.name) + + editor = os.environ.get("EDITOR", "vim") + subprocess.call([editor, temp_path]) + + with temp_path.open("rb") as f: + new_contents = f.read() + encrypted_contents = self.encryptor.encrypt(new_contents) + + temp_path.unlink() + return encrypted_contents + + def run(self): + with self.note_path.open("rb") as f: + original_contents = f.read() + original_contents = self.encryptor.decrypt(original_contents) + new_contents = self.edit_contents(original_contents) + with self.note_path.open("wb") as f: + f.write(new_contents) diff --git a/halig/commands/notebooks.py b/halig/commands/notebooks.py new file mode 100644 index 0000000..ee56d69 --- /dev/null +++ b/halig/commands/notebooks.py @@ -0,0 +1,31 @@ +from collections import deque +from pathlib import Path + +from rich import print +from rich.tree import Tree + +from halig.commands.base import BaseCommand + + +class NotebooksCommand(BaseCommand): + def __init__(self, max_depth: int | float, *args, **kwargs): + self.max_depth = max_depth + super().__init__(*args, **kwargs) + + def build_tree(self, root_path: Path): + tree = Tree(root_path.name) + q: deque[tuple[Path, Tree, int | float]] = deque([(root_path, tree, 0)]) + while q: + current_folder_path, current_tree_node, depth = q.popleft() + if depth >= self.max_depth: + break + for item in sorted(current_folder_path.iterdir()): + if item.is_dir(): + item_tree_node = current_tree_node.add(item.name) + q.append((item, item_tree_node, depth + 1)) + else: + current_tree_node.add(item.name) + return tree + + def run(self): + print(self.build_tree(self.settings.notebooks_root_path)) diff --git a/halig/commands/show.py b/halig/commands/show.py new file mode 100644 index 0000000..481e61b --- /dev/null +++ b/halig/commands/show.py @@ -0,0 +1,34 @@ +from pathlib import Path + +from rich.console import Console +from rich.markdown import Markdown + +from halig.commands.base import BaseCommand +from halig.encryption import Encryptor +from halig.settings import Settings + + +class ShowCommand(BaseCommand): + def __init__(self, note_path: Path, settings: Settings): + super().__init__(settings) + + self.note_path = self.settings.notebooks_root_path / note_path + self.encryptor = Encryptor(self.settings) + self.console = Console() + if self.note_path.is_dir(): + self.note_path /= f"{self.today.date()}.age" + + if not self.note_path.exists(): + err = f"File {self.note_path.name} does not exist" + raise ValueError(err) + + if not self.note_path.name.endswith(".age"): + err = f"File {self.note_path.name} is not a valid AGE file" + raise ValueError(err) + + def run(self): + with self.note_path.open("rb") as f: + data = f.read() + contents = self.encryptor.decrypt(data) + md_contents = Markdown(contents.decode()) + self.console.print(md_contents) diff --git a/halig/config.py b/halig/config.py deleted file mode 100644 index 20939aa..0000000 --- a/halig/config.py +++ /dev/null @@ -1,83 +0,0 @@ -import os -from datetime import datetime -from pathlib import Path - -import yaml -from pydantic import ( - BaseSettings, - FilePath, - DirectoryPath, - validator, - Field, -) - -from halig.exceptions import ConfigFileIsInvalid, ConfigFileDoesNotExist - -DEFAULT_CONFIGURATION_PATH = Path("~/.config/halig/halig.yml").expanduser() - - -class EncryptionKeysConfig(BaseSettings): - public_key_path: FilePath = Field(default="~/.ssh/id_ed25519.pub") - private_key_path: FilePath = Field(default="~/.ssh/id_ed25519") - - @validator("*", pre=True) - def expanduser_paths(cls, v) -> Path: - if isinstance(v, str): - return Path(v).expanduser() - if isinstance(v, Path): - return v.expanduser() - return v # pragma: no cover - - -class Config(BaseSettings): - notes_root_path: DirectoryPath = Field(default="~/Documents/notes") - encryption_keys: EncryptionKeysConfig = Field(default_factory=EncryptionKeysConfig) - age_binary_path: FilePath = Field(default="/usr/bin/age") - _default_template_data: str = f"""@document.meta -title: {datetime.now():%Y-%m-%d} -description: {datetime.now():%Y-%m-%d} -authors: {os.getenv("USER")} -categories: [ - -] -created: {datetime.now():%Y-%m-%d} -version: 1.0.0 -@end -""" - - @validator("notes_root_path", "age_binary_path", pre=True) - def expanduser_paths(cls, v) -> Path: - if isinstance(v, str): - return Path(v).expanduser() - if isinstance(v, Path): - return v.expanduser() - return v # pragma: no cover - - -def get_config(config_path: Path = DEFAULT_CONFIGURATION_PATH) -> Config: - """Init and retrieve a config object. If the `config_path` argument is not provided, - the default config initialization will be provided - - Args: - config_path (Path): The config path, defaults to DEFAULT_CONFIGURATION_PATH - Returns: - a Config object - Raises: - HaligNotInitialized if the default path does not exist - ConfigFileDoesNotExist if the provided path does not exist - """ - - if not config_path: - return Config() # pragma: no cover - - if not config_path.exists(): - raise ConfigFileDoesNotExist - - with open(config_path, "r") as f: - yml = yaml.load(f, Loader=yaml.SafeLoader) - if not yml: - raise ConfigFileIsInvalid - try: - return Config(**yml) - except TypeError: - raise ConfigFileIsInvalid diff --git a/halig/edit_note.py b/halig/edit_note.py deleted file mode 100644 index e96d944..0000000 --- a/halig/edit_note.py +++ /dev/null @@ -1,29 +0,0 @@ -from pathlib import Path -from tempfile import NamedTemporaryFile - -from sh import age -from halig.config import Config -from halig.utils import wait_for_editor - - -def edit_note(note_path: Path, config: Config): - """Edit an existing note. This method assumes that `note_path` exists, is - a fully-formed, absolute path and an age file inside the configured notebooks - - Args: - note_path (Path): The path to the note to edit - config (Config): config object - """ - - note_contents = age("-d", "-i", config.encryption_keys.private_key_path, note_path) - - with NamedTemporaryFile(delete=False) as tmpfile: - tmpfile.write(str(note_contents).encode()) - wait_for_editor(tmpfile.name) - age( - "-R", - str(config.encryption_keys.public_key_path), - tmpfile.name, - _out=str(note_path), - ) - Path(tmpfile.name).unlink() diff --git a/halig/encryption.py b/halig/encryption.py new file mode 100644 index 0000000..8e25f63 --- /dev/null +++ b/halig/encryption.py @@ -0,0 +1,34 @@ +from pyrage import decrypt as rage_decrypt +from pyrage import encrypt as rage_encrypt +from pyrage import ssh, x25519 + +from halig.settings import Settings + + +class Encryptor: + def __init__(self, settings: Settings): + self.settings = settings + + # load identity + with settings.identity_path.open("r") as f: + identity_contents = f.read() + if identity_contents.startswith("-----BEGIN OPENSSH PRIVATE KEY-----"): + self.identity = ssh.Identity.from_buffer(identity_contents.encode()) + else: + self.identity = x25519.Identity.from_str(identity_contents) + + # load recipient + with settings.recipient_path.open("r") as f: + recipient_contents = f.read() + if recipient_contents.startswith("ssh-ed25519"): + self.recipient = ssh.Recipient.from_str(recipient_contents) + else: + self.recipient = x25519.Recipient.from_str(recipient_contents) + + def encrypt(self, data: str | bytes) -> bytes: + if isinstance(data, str): + data = data.encode() + return rage_encrypt(data, [self.recipient]) # type: ignore[no-any-return] + + def decrypt(self, data: bytes) -> bytes: + return rage_decrypt(data, [self.identity]) # type: ignore[no-any-return] diff --git a/halig/exceptions.py b/halig/exceptions.py deleted file mode 100644 index 8d852a1..0000000 --- a/halig/exceptions.py +++ /dev/null @@ -1,75 +0,0 @@ -from abc import abstractmethod, ABC -from functools import wraps - -from pydantic import ValidationError -import traceback -from halig import logger - - -class HaligError(Exception, ABC): - @property - @abstractmethod - def msg(self) -> str: # pragma: no cover - ... - - error_code = 1 - - -class HaligNotInitialized(HaligError): - msg = """Error: please initialize the program first, this can be done -by calling: - - halig init - -... which will create a $HOME/.config/halig/halig.yml -configuration example file. You can also call the program with a custom -settings path like this: - - halig edit --configuration_path /some/other/path/halig.yml""" - - error_code = 2 - - -class ConfigFileDoesNotExist(HaligError): - msg = "Config file does not exist" - error_code = 3 - - -class ConfigFileIsInvalid(HaligError): - msg = "Config file is invalid" - error_code = 4 - - -class NoteDoesNotExist(HaligError): - msg = "Provided note path does not exist" - error_code = 5 - - -class CouldNotEditTempfile(HaligError): - msg = "Could not edit temporary file; original file was not replaced" - error_code = 6 - - -class InvalidNotePath(HaligError): - msg = "Note path is invalid" - error_code = 7 - - -def handle_errors(func): # pragma: no cover - # TODO: parse age/sh errors - @wraps(func) - def inner_function(*args, **kwargs): - try: - return func(*args, **kwargs) - except HaligError as e: - logger.error(e.msg) - exit(e.error_code) - except ValidationError as e: - [logger.error(f"Error: {error['msg']}") for error in e.errors()] - exit(1) - except Exception: - logger.error("Unhandled error") - traceback.print_exc() - exit(2) - - return inner_function diff --git a/halig/logger.py b/halig/logger.py deleted file mode 100644 index 2f8f860..0000000 --- a/halig/logger.py +++ /dev/null @@ -1,27 +0,0 @@ -import rich -import seedir as sd -from pathlib import Path - - -def info(text: str): # pragma: no cover - print(text) - - -def error(text: str): # pragma: no cover - rich.print(f"[red]{text}") - - -def tree( - dir_path: Path, print_files: bool = False, print_hidden: bool = False -): # pragma: no cover - def mask(x: str) -> bool: - path = Path(x) - if path.name.startswith(".") and not print_hidden: - return False - if path.is_dir(): - return True - if Path(x).is_file() and print_files: - return True - return False - - sd.seedir(path=str(dir_path), mask=mask) diff --git a/halig/main.py b/halig/main.py old mode 100755 new mode 100644 index 7e24d2b..cadc5cf --- a/halig/main.py +++ b/halig/main.py @@ -1,81 +1,35 @@ -#!/usr/bin/env python3 -from datetime import datetime +#!/usr/bin/env python from pathlib import Path -import yaml -from typer import Typer - -from halig import logger -from halig.config import ( - get_config, - DEFAULT_CONFIGURATION_PATH, - Config, -) -from halig.edit_note import edit_note -from halig.exceptions import InvalidNotePath -from halig.exceptions import handle_errors -from halig.new_note import new_note -from halig.utils import resolve_path - -app = Typer(pretty_exceptions_enable=False) +from halig import app +from halig.commands.edit import EditCommand +from halig.commands.notebooks import NotebooksCommand +from halig.commands.show import ShowCommand +from halig.settings import load_from_file @app.command() -def init(force_recreate: bool = False): - """Create the config file. If the config file already exists, it'll not - be overwritten unless the `--force-recreate` flag is provided - """ - if DEFAULT_CONFIGURATION_PATH.exists() and not force_recreate: - logger.error( - """$HOME/.config/halig/halig.yml already exists. - -Execute again with --force-recreate in order to replace the configuration file's -contents with the default one""" - ) - exit(1) - - DEFAULT_CONFIGURATION_PATH.parent.mkdir(parents=True, exist_ok=True) - DEFAULT_CONFIGURATION_PATH.touch(mode=0o700, exist_ok=True) - with open(DEFAULT_CONFIGURATION_PATH, "w") as f: - yaml.dump(Config().dict(), f, Dumper=yaml.SafeDumper) +def notebooks(max_depth: int = -1): + if max_depth < 0: + max_depth = float("inf") # type: ignore[assignment] + settings = load_from_file() + command = NotebooksCommand(settings=settings, max_depth=max_depth) + command.run() @app.command() -@handle_errors -def notebooks( - print_files: bool = False, - print_hidden: bool = False, - configuration_path: Path = DEFAULT_CONFIGURATION_PATH, -): - """Print notebooks and their contents, tree-style""" - config = get_config(configuration_path) - logger.tree( - config.notes_root_path, print_files=print_files, print_hidden=print_hidden - ) +def edit(note: Path): + settings = load_from_file() + command = EditCommand(settings=settings, note_path=note) + command.run() @app.command() -@handle_errors -def edit(path: Path, configuration_path: Path = DEFAULT_CONFIGURATION_PATH): - """Edit a new or existing note by providing a relative path. The relative path - will be appended to the notes root path that is specified in the configuration file. - Note that if only a dir is provided, an attempt to create or open - `/.age` will be made. - """ - - config = get_config(configuration_path) - if path.is_absolute(): - raise InvalidNotePath - - full_path = resolve_path(path) - - if full_path.is_dir(): - return new_note(full_path / f"{datetime.now():%Y-%m-%d}.age", config) - - if full_path.exists(): - return edit_note(full_path, config) - - new_note(full_path, config) +def show(note: Path): + settings = load_from_file() + command = ShowCommand(settings=settings, note_path=note) + command.run() -app() +if __name__ == "__main__": + app() diff --git a/halig/new_note.py b/halig/new_note.py deleted file mode 100644 index 072d630..0000000 --- a/halig/new_note.py +++ /dev/null @@ -1,42 +0,0 @@ -from pathlib import Path -from tempfile import NamedTemporaryFile - -from sh import age - -from halig.config import Config -from halig.utils import get_template_data, wait_for_editor - - -def new_note(note_path: Path, config: Config): - """Create a new note from a given path. This function assumes that `note_path` - **does not exist** but is a fully-formed, absolute path and an age file inside any - of the configured notebooks - - - 1. the file is touched - 2. a temporary file is created and the template data is dumped into - 3. the program waits for $EDITOR to open, edit and finish the tempfile - 4. the temp file contents are encrypted and dumped into the age file - - Args: - note_path (Path): The path to the note - config (Config): The config object - """ - - note_path.touch(exist_ok=True) - template_data: str = ( - get_template_data(note_path.parent) or config._default_template_data - ) - - with NamedTemporaryFile(delete=False) as tempfile: - tempfile.write(template_data.encode()) - - wait_for_editor(tempfile.name) - - age( - "-R", - str(config.encryption_keys.public_key_path), - tempfile.name, - _out=str(note_path), - ) - Path(tempfile.name).unlink() diff --git a/halig/settings.py b/halig/settings.py new file mode 100644 index 0000000..a83879c --- /dev/null +++ b/halig/settings.py @@ -0,0 +1,37 @@ +import os +from functools import lru_cache +from pathlib import Path + +import yaml +from pydantic import BaseSettings, FilePath + + +class Settings(BaseSettings): + notebooks_root_path: Path + identity_path: FilePath = Path("~/.ssh/id_ed25519").expanduser() + recipient_path: FilePath = Path("~/.ssh/id_ed25519.pub").expanduser() + + class Config: + env_prefix = "halig_" + + +@lru_cache +def load_from_file(file_path: Path | None = None) -> Settings: + if file_path is None: + xdg_config_home = Path(os.getenv("XDG_CONFIG_HOME", "~/.config")).expanduser() + if not xdg_config_home.exists(): + err = f"File {xdg_config_home} does not exist" + raise FileNotFoundError(err) + + file_path = xdg_config_home / "halig" / "halig.yml" + file_path.touch(exist_ok=True) + elif not file_path.exists(): + err = f"File {file_path} does not exist" + raise FileNotFoundError(err) + + with file_path.open("r") as f: + data = yaml.safe_load(f) + if not data: + err = f"File {file_path} is empty" + raise ValueError(err) + return Settings(**data) diff --git a/halig/utils.py b/halig/utils.py deleted file mode 100644 index cd9cc6d..0000000 --- a/halig/utils.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import subprocess -from pathlib import Path - -from halig import logger -from halig.exceptions import CouldNotEditTempfile - - -def resolve_path(path: Path) -> Path: - """Resolve a path's relative attributes, like envvars, relative notations, etc - - Args: - path(Path): The path to resolve - Returns: - Path: The resolved path - """ - return Path(os.path.expandvars(path)).expanduser().resolve() - - -def get_template_data(path: Path) -> str | None: - """Read template data from path/template.halig - - Args: - path(Path): The path to read template data from, usually a notebook - Returns: - maybe returns a string containing the template data - """ - template_path = path / "template.halig" - if not (template_path.exists() and template_path.is_file()): - return None - - with open(template_path) as f: - return f.read() - - -def wait_for_editor(filepath: str): - """Wait for $EDITOR to be opened and then manually closed by the user - - Args: - filepath(Path): The filepath which $EDITOR should modify - Raises: - CouldNotEditTempfile if the subprocess call errors out - """ - try: - subprocess.call([os.environ.get("EDITOR", "vim"), filepath]) - except subprocess.CalledProcessError as e: - logger.error(e.output) - raise CouldNotEditTempfile diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..00739fc --- /dev/null +++ b/noxfile.py @@ -0,0 +1,16 @@ +import nox + +VERSIONS = ["3.10", "3.11"] + + +@nox.session(python=VERSIONS) +def tests(session): + session.run('pdm', 'export', '-G', 'tests', '-f', 'requirements', '-o', 'requirements.txt', external=True) + session.install('-r', "requirements.txt") + session.run("make", "tests", external=True) + session.run('rm', "requirements.txt", external=True) + + +@nox.session(python=VERSIONS) +def linters(session): + session.run("make", "linters", external=True) diff --git a/pdm.lock b/pdm.lock new file mode 100644 index 0000000..4c395e5 --- /dev/null +++ b/pdm.lock @@ -0,0 +1,722 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[[package]] +name = "attrs" +version = "22.2.0" +requires_python = ">=3.6" +summary = "Classes Without Boilerplate" + +[[package]] +name = "black" +version = "23.3.0" +requires_python = ">=3.7" +summary = "The uncompromising code formatter." +dependencies = [ + "click>=8.0.0", + "mypy-extensions>=0.4.3", + "packaging>=22.0", + "pathspec>=0.9.0", + "platformdirs>=2", + "tomli>=1.1.0; python_version < \"3.11\"", +] + +[[package]] +name = "click" +version = "8.1.3" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +dependencies = [ + "colorama; platform_system == \"Windows\"", +] + +[[package]] +name = "clumper" +version = "0.2.15" +summary = "UNKNOWN" + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." + +[[package]] +name = "coverage" +version = "7.2.2" +requires_python = ">=3.7" +summary = "Code coverage measurement for Python" + +[[package]] +name = "coverage" +version = "7.2.2" +extras = ["toml"] +requires_python = ">=3.7" +summary = "Code coverage measurement for Python" +dependencies = [ + "coverage==7.2.2", + "tomli; python_full_version <= \"3.11.0a6\"", +] + +[[package]] +name = "exceptiongroup" +version = "1.1.1" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" + +[[package]] +name = "iniconfig" +version = "2.0.0" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" + +[[package]] +name = "markdown-it-py" +version = "2.2.0" +requires_python = ">=3.7" +summary = "Python port of markdown-it. Markdown parsing, done right!" +dependencies = [ + "mdurl~=0.1", +] + +[[package]] +name = "mdurl" +version = "0.1.2" +requires_python = ">=3.7" +summary = "Markdown URL utilities" + +[[package]] +name = "mypy" +version = "1.1.1" +requires_python = ">=3.7" +summary = "Optional static typing for Python" +dependencies = [ + "mypy-extensions>=1.0.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=3.10", +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." + +[[package]] +name = "nodeenv" +version = "1.7.0" +requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +summary = "Node.js virtual environment builder" +dependencies = [ + "setuptools", +] + +[[package]] +name = "packaging" +version = "23.0" +requires_python = ">=3.7" +summary = "Core utilities for Python packages" + +[[package]] +name = "parse" +version = "1.19.0" +summary = "parse() is the opposite of format()" + +[[package]] +name = "pathspec" +version = "0.11.1" +requires_python = ">=3.7" +summary = "Utility library for gitignore style pattern matching of file paths." + +[[package]] +name = "pendulum" +version = "2.1.2" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +summary = "Python datetimes made easy" +dependencies = [ + "python-dateutil<3.0,>=2.6", + "pytzdata>=2020.1", +] + +[[package]] +name = "platformdirs" +version = "3.2.0" +requires_python = ">=3.7" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." + +[[package]] +name = "pluggy" +version = "1.0.0" +requires_python = ">=3.6" +summary = "plugin and hook calling mechanisms for python" + +[[package]] +name = "pprintpp" +version = "0.4.0" +summary = "A drop-in replacement for pprint that's actually pretty" + +[[package]] +name = "pydantic" +version = "1.10.7" +requires_python = ">=3.7" +summary = "Data validation and settings management using python type hints" +dependencies = [ + "typing-extensions>=4.2.0", +] + +[[package]] +name = "pyfakefs" +version = "5.1.0" +requires_python = ">=3.7" +summary = "pyfakefs implements a fake file system that mocks the Python file system modules." + +[[package]] +name = "pygments" +version = "2.14.0" +requires_python = ">=3.6" +summary = "Pygments is a syntax highlighting package written in Python." + +[[package]] +name = "pyrage" +version = "1.0.3" +requires_python = ">=3.7" +summary = "Python bindings for rage (age in Rust)" + +[[package]] +name = "pyrage-stubs" +version = "1.0.1" +requires_python = ">= 3.7" +summary = "A PEP 561 stub package for pyrage's types" +dependencies = [ + "pyrage<2.0,>=1.0.0", +] + +[[package]] +name = "pyright" +version = "1.1.301" +requires_python = ">=3.7" +summary = "Command line wrapper for pyright" +dependencies = [ + "nodeenv>=1.6.0", +] + +[[package]] +name = "pytest" +version = "7.2.2" +requires_python = ">=3.7" +summary = "pytest: simple powerful testing with Python" +dependencies = [ + "attrs>=19.2.0", + "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", + "iniconfig", + "packaging", + "pluggy<2.0,>=0.12", + "tomli>=1.0.0; python_version < \"3.11\"", +] + +[[package]] +name = "pytest-clarity" +version = "1.0.1" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "A plugin providing an alternative, colourful diff output for failing assertions." +dependencies = [ + "pprintpp>=0.4.0", + "pytest>=3.5.0", + "rich>=8.0.0", +] + +[[package]] +name = "pytest-cov" +version = "4.0.0" +requires_python = ">=3.6" +summary = "Pytest plugin for measuring coverage." +dependencies = [ + "coverage[toml]>=5.2.1", + "pytest>=4.6", +] + +[[package]] +name = "pytest-duration-insights" +version = "0.1.1" +summary = "UNKNOWN" +dependencies = [ + "clumper>=0.2.12", + "parse>=1.19.0", + "pytest-reportlog>=0.1.2", + "typer>=0.3.2", +] + +[[package]] +name = "pytest-pretty" +version = "1.1.1" +requires_python = ">=3.7" +summary = "pytest plugin for printing summary data as I want it" +dependencies = [ + "pytest>=7", + "rich>=12", +] + +[[package]] +name = "pytest-reportlog" +version = "0.2.1" +requires_python = ">=3.7" +summary = "Replacement for the --resultlog option, focused in simplicity and extensibility" +dependencies = [ + "pytest", +] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +dependencies = [ + "six>=1.5", +] + +[[package]] +name = "pytzdata" +version = "2020.1" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "The Olson timezone database for Python." + +[[package]] +name = "pyyaml" +version = "6.0" +requires_python = ">=3.6" +summary = "YAML parser and emitter for Python" + +[[package]] +name = "rich" +version = "13.3.3" +requires_python = ">=3.7.0" +summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +dependencies = [ + "markdown-it-py<3.0.0,>=2.2.0", + "pygments<3.0.0,>=2.13.0", +] + +[[package]] +name = "ruff" +version = "0.0.260" +requires_python = ">=3.7" +summary = "An extremely fast Python linter, written in Rust." + +[[package]] +name = "setuptools" +version = "67.6.1" +requires_python = ">=3.7" +summary = "Easily download, build, install, upgrade, and uninstall Python packages" + +[[package]] +name = "six" +version = "1.16.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" + +[[package]] +name = "tomli" +version = "2.0.1" +requires_python = ">=3.7" +summary = "A lil' TOML parser" + +[[package]] +name = "typer" +version = "0.7.0" +requires_python = ">=3.6" +summary = "Typer, build great CLIs. Easy to code. Based on Python type hints." +dependencies = [ + "click<9.0.0,>=7.1.1", +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.9" +summary = "Typing stubs for PyYAML" + +[[package]] +name = "typing-extensions" +version = "4.5.0" +requires_python = ">=3.7" +summary = "Backported and Experimental Type Hints for Python 3.7+" + +[metadata] +lock_version = "4.2" +groups = ["default", "linters", "linting", "testing"] +content_hash = "sha256:bd20ae8c3a5d73b6301022d3e5fd8844e31baf827ff41860ca8afd55d5b3ffe9" + +[metadata.files] +"attrs 22.2.0" = [ + {url = "https://files.pythonhosted.org/packages/21/31/3f468da74c7de4fcf9b25591e682856389b3400b4b62f201e65f15ea3e07/attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, + {url = "https://files.pythonhosted.org/packages/fb/6e/6f83bf616d2becdf333a1640f1d463fef3150e2e926b7010cb0f81c95e88/attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, +] +"black 23.3.0" = [ + {url = "https://files.pythonhosted.org/packages/06/1e/273d610249f0335afb1ddb03664a03223f4826e3d1a95170a0142cb19fb4/black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, + {url = "https://files.pythonhosted.org/packages/12/4b/99c71d1cf1353edd5aff2700b8960f92e9b805c9dab72639b67dbb449d3a/black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, + {url = "https://files.pythonhosted.org/packages/13/0a/ed8b66c299e896780e4528eed4018f5b084da3b9ba4ee48328550567d866/black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, + {url = "https://files.pythonhosted.org/packages/13/25/cfa06788d0a936f2445af88f13604b5bcd5c9d050db618c718e6ebe66f74/black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, + {url = "https://files.pythonhosted.org/packages/21/14/d5a2bec5fb15f9118baab7123d344646fac0b1c6939d51c2b05259cd2d9c/black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, + {url = "https://files.pythonhosted.org/packages/24/eb/2d2d2c27cb64cfd073896f62a952a802cd83cf943a692a2f278525b57ca9/black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, + {url = "https://files.pythonhosted.org/packages/27/70/07aab2623cfd3789786f17e051487a41d5657258c7b1ef8f780512ffea9c/black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, + {url = "https://files.pythonhosted.org/packages/29/b1/b584fc863c155653963039664a592b3327b002405043b7e761b9b0212337/black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, + {url = "https://files.pythonhosted.org/packages/3c/d7/85f3d79f9e543402de2244c4d117793f262149e404ea0168841613c33e07/black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, + {url = "https://files.pythonhosted.org/packages/3f/0d/81dd4194ce7057c199d4f28e4c2a885082d9d929e7a55c514b23784f7787/black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, + {url = "https://files.pythonhosted.org/packages/49/36/15d2122f90ff1cd70f06892ebda777b650218cf84b56b5916a993dc1359a/black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, + {url = "https://files.pythonhosted.org/packages/49/d7/f3b7da6c772800f5375aeb050a3dcf682f0bbeb41d313c9c2820d0156e4e/black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, + {url = "https://files.pythonhosted.org/packages/69/49/7e1f0cf585b0d607aad3f971f95982cc4208fc77f92363d632d23021ee57/black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, + {url = "https://files.pythonhosted.org/packages/6d/b4/0f13ab7f5e364795ff82b76b0f9a4c9c50afda6f1e2feeb8b03fdd7ec57d/black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, + {url = "https://files.pythonhosted.org/packages/ad/e7/4642b7f462381799393fbad894ba4b32db00870a797f0616c197b07129a9/black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, + {url = "https://files.pythonhosted.org/packages/c0/53/42e312c17cfda5c8fc4b6b396a508218807a3fcbb963b318e49d3ddd11d5/black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, + {url = "https://files.pythonhosted.org/packages/ca/44/eb41edd3f558a6139f09eee052dead4a7a464e563b822ddf236f5a8ee286/black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, + {url = "https://files.pythonhosted.org/packages/ce/f4/2b0c6ac9e1f8584296747f66dd511898b4ebd51d6510dba118279bff53b6/black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, + {url = "https://files.pythonhosted.org/packages/d1/6e/5810b6992ed70403124c67e8b3f62858a32b35405177553f1a78ed6b6e31/black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, + {url = "https://files.pythonhosted.org/packages/d6/36/66370f5017b100225ec4950a60caeef60201a10080da57ddb24124453fba/black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, + {url = "https://files.pythonhosted.org/packages/d7/6f/d3832960a3b646b333b7f0d80d336a3c123012e9d9d5dba4a622b2b6181d/black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, + {url = "https://files.pythonhosted.org/packages/db/f4/7908f71cc71da08df1317a3619f002cbf91927fb5d3ffc7723905a2113f7/black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, + {url = "https://files.pythonhosted.org/packages/de/b4/76f152c5eb0be5471c22cd18380d31d188930377a1a57969073b89d6615d/black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, + {url = "https://files.pythonhosted.org/packages/eb/a5/17b40bfd9b607b69fa726b0b3a473d14b093dcd5191ea1a1dd664eccfee3/black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, + {url = "https://files.pythonhosted.org/packages/fd/5b/fc2d7922c1a6bb49458d424b5be71d251f2d0dc97be9534e35d171bdc653/black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, +] +"click 8.1.3" = [ + {url = "https://files.pythonhosted.org/packages/59/87/84326af34517fca8c58418d148f2403df25303e02736832403587318e9e8/click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, + {url = "https://files.pythonhosted.org/packages/c2/f1/df59e28c642d583f7dacffb1e0965d0e00b218e0186d7858ac5233dce840/click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, +] +"clumper 0.2.15" = [ + {url = "https://files.pythonhosted.org/packages/8c/f1/074d345999b301d514aa6d787e7dd4355f87f66ad642f4aabbdcba74aa48/clumper-0.2.15.tar.gz", hash = "sha256:5b243bc1eb666447dcdf32ac3239e5133b577f58c87ddb3b4cfb4a208b24ee2c"}, + {url = "https://files.pythonhosted.org/packages/a6/95/0e8eb5227a38940b13469e8277de3262f99af9da41e059e7e0cd61fdcf14/clumper-0.2.15-py2.py3-none-any.whl", hash = "sha256:323152d64330b908a772cf6b4ea9e5b6d8abde7b4d2ddca253251e75c895edb8"}, +] +"colorama 0.4.6" = [ + {url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] +"coverage 7.2.2" = [ + {url = "https://files.pythonhosted.org/packages/06/ab/1dd1a592ca3dff0c0d1da895c609f6b8b6b3092a2cc06f5494826b7689c8/coverage-7.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9d22e94e6dc86de981b1b684b342bec5e331401599ce652900ec59db52940005"}, + {url = "https://files.pythonhosted.org/packages/0d/49/ef6f4681a90ad12b734e8fd85913dc310eb58bfc33eb95534bdfef073476/coverage-7.2.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:046936ab032a2810dcaafd39cc4ef6dd295df1a7cbead08fe996d4765fca9fe4"}, + {url = "https://files.pythonhosted.org/packages/0d/d3/7c6d91fc5dd15496954e9a941a765fce70913314181289e441db0e5c6568/coverage-7.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0484d9dd1e6f481b24070c87561c8d7151bdd8b044c93ac99faafd01f695c78e"}, + {url = "https://files.pythonhosted.org/packages/11/da/b52e1f1492d6431ce0ebdd9da8744faf9f9fb75c3077165aca44c178f6e7/coverage-7.2.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:186e0fc9cf497365036d51d4d2ab76113fb74f729bd25da0975daab2e107fd90"}, + {url = "https://files.pythonhosted.org/packages/13/31/8a4be0305f60f9a856965e076388cf3b93bac36a1324897854accecc4e94/coverage-7.2.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:387fb46cb8e53ba7304d80aadca5dca84a2fbf6fe3faf6951d8cf2d46485d1e5"}, + {url = "https://files.pythonhosted.org/packages/15/35/5a6ac4b81c41fe067af22a5e9ac440609a122c1ece220b8c565dfb27f205/coverage-7.2.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7c20b731211261dc9739bbe080c579a1835b0c2d9b274e5fcd903c3a7821cf88"}, + {url = "https://files.pythonhosted.org/packages/18/a9/98d8eddba099f79548527af0aa546c31c3d8a2cc9e5d1c59a10a584ffc6d/coverage-7.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3668291b50b69a0c1ef9f462c7df2c235da3c4073f49543b01e7eb1dee7dd540"}, + {url = "https://files.pythonhosted.org/packages/1b/21/e757c7147ff8ef4be811d5fb3731ec0936ba6689444fc20dff953536a243/coverage-7.2.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e1df45c23d4230e3d56d04414f9057eba501f78db60d4eeecfcb940501b08fd"}, + {url = "https://files.pythonhosted.org/packages/1c/02/46d5dc331c9419d01e66c497f3974af895aaccf6a2a2695cfd6f83f1935f/coverage-7.2.2-cp39-cp39-win32.whl", hash = "sha256:db45eec1dfccdadb179b0f9ca616872c6f700d23945ecc8f21bb105d74b1c5fc"}, + {url = "https://files.pythonhosted.org/packages/29/3f/e2cef2978bfd787da8e02892448098ecb4a5909970c08b6220d0867460c3/coverage-7.2.2-cp310-cp310-win32.whl", hash = "sha256:38004671848b5745bb05d4d621526fca30cee164db42a1f185615f39dc997292"}, + {url = "https://files.pythonhosted.org/packages/30/0c/6e0a65466f8008b2001c0354782753a880617b15dba857eb7e97928313fc/coverage-7.2.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc4803779f0e4b06a2361f666e76f5c2e3715e8e379889d02251ec911befd149"}, + {url = "https://files.pythonhosted.org/packages/34/7d/380f87502e91d1da48eb5d0dead8cee4911eb19e2d4b60e3f1ee9c975c85/coverage-7.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:420f94a35e3e00a2b43ad5740f935358e24478354ce41c99407cddd283be00d2"}, + {url = "https://files.pythonhosted.org/packages/38/0f/2e384888c47e111a7a4c025812d33f197aa39a59338cfd5e08874c940f6c/coverage-7.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d2b96123a453a2d7f3995ddb9f28d01fd112319a7a4d5ca99796a7ff43f02af5"}, + {url = "https://files.pythonhosted.org/packages/3c/12/51c5bdce0ad62a29bff429e99a9b2f23a0220cca89e768fc22694d4aeb4f/coverage-7.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:507e4720791977934bba016101579b8c500fb21c5fa3cd4cf256477331ddd988"}, + {url = "https://files.pythonhosted.org/packages/42/1b/340c1d2d3bdfe33664a63307ae1143bf3e7929290715d8034e40aff6bcef/coverage-7.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ba279aae162b20444881fc3ed4e4f934c1cf8620f3dab3b531480cf602c76b7f"}, + {url = "https://files.pythonhosted.org/packages/44/50/b752e846395b17d3789b070b82ac54e88cc2e4f4d906b9f864074caf04b9/coverage-7.2.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fa54fb483decc45f94011898727802309a109d89446a3c76387d016057d2c84"}, + {url = "https://files.pythonhosted.org/packages/47/21/632047c45edb08f0eb51f9e8e49591d23c15ff078b32e0a88ddf99f4e8c2/coverage-7.2.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db8c2c5ace167fd25ab5dd732714c51d4633f58bac21fb0ff63b0349f62755a8"}, + {url = "https://files.pythonhosted.org/packages/4a/73/031f7380e2912f78801d28120091ba2dcf5bc0ad689e958d6b970ce67cb7/coverage-7.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:797aad79e7b6182cb49c08cc5d2f7aa7b2128133b0926060d0a8889ac43843be"}, + {url = "https://files.pythonhosted.org/packages/4f/ec/acf6816f7fd5e628746db61725f7a3f5eb16b3b55c919c885072c60d17fa/coverage-7.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4c752d5264053a7cf2fe81c9e14f8a4fb261370a7bb344c2a011836a96fb3f57"}, + {url = "https://files.pythonhosted.org/packages/50/32/82dea3a1e928f8f7d2cdf6f0c6498fd42c5e9d661de0191f8c47d3966306/coverage-7.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:81f63e0fb74effd5be736cfe07d710307cc0a3ccb8f4741f7f053c057615a137"}, + {url = "https://files.pythonhosted.org/packages/54/8a/db9d9cd24f96bb872eea151bb0d5c8cb6a96825b70a0cfaf07bceab2884d/coverage-7.2.2.tar.gz", hash = "sha256:36dd42da34fe94ed98c39887b86db9d06777b1c8f860520e21126a75507024f2"}, + {url = "https://files.pythonhosted.org/packages/56/65/fedba1cb8d954823eded8e7b943749531f81060f8e4214fe9ee8dd1da5bc/coverage-7.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:c448b5c9e3df5448a362208b8d4b9ed85305528313fca1b479f14f9fe0d873b8"}, + {url = "https://files.pythonhosted.org/packages/59/4b/8a1077b2cf0c21e2f39105f3c94fac4e1bb18ff341d386ba60374487ae49/coverage-7.2.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:53d0fd4c17175aded9c633e319360d41a1f3c6e352ba94edcb0fa5167e2bad67"}, + {url = "https://files.pythonhosted.org/packages/5e/92/cffba484a7a34ca08097f7991b72cbd85da4adc717c69c067bab2e1f612c/coverage-7.2.2-pp37.pp38.pp39-none-any.whl", hash = "sha256:872d6ce1f5be73f05bea4df498c140b9e7ee5418bfa2cc8204e7f9b817caa968"}, + {url = "https://files.pythonhosted.org/packages/5e/f1/cf01ea71b3c525f5cb4aa9956b5bf2d4e0ac59cdc1e2aead8e73374ab420/coverage-7.2.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:efe1c0adad110bf0ad7fb59f833880e489a61e39d699d37249bdf42f80590169"}, + {url = "https://files.pythonhosted.org/packages/6f/e4/9576c24b37c941e70a4815cbbd44ff2779c83b821ab3a38022b6f530d61c/coverage-7.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfe7085783cda55e53510482fa7b5efc761fad1abe4d653b32710eb548ebdd2d"}, + {url = "https://files.pythonhosted.org/packages/70/74/7ceb96c38dac56e5894c3b0af6c4adfd0dd7f96521e8b829544d1dcec8fe/coverage-7.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4f68ee32d7c4164f1e2c8797535a6d0a3733355f5861e0f667e37df2d4b07140"}, + {url = "https://files.pythonhosted.org/packages/74/bf/ae3344872e1a33e58481afaa1587e39a4e626fdaa69bd11c1454fd34e0d3/coverage-7.2.2-cp37-cp37m-win32.whl", hash = "sha256:5cc0783844c84af2522e3a99b9b761a979a3ef10fb87fc4048d1ee174e18a7d8"}, + {url = "https://files.pythonhosted.org/packages/75/93/1821ffa10c91b0c4220f1b525f82b408ca49a605481d76687078cd251504/coverage-7.2.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d530191aa9c66ab4f190be8ac8cc7cfd8f4f3217da379606f3dd4e3d83feba69"}, + {url = "https://files.pythonhosted.org/packages/76/6b/30aa019a24ba3ba3487b6d61e468c898dcba77a153012f2032d72695ec13/coverage-7.2.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e627dee428a176ffb13697a2c4318d3f60b2ccdde3acdc9b3f304206ec130ccd"}, + {url = "https://files.pythonhosted.org/packages/83/db/85c50845c1ca6c83082decfed61a8d928903ef6d72f8a2c20a615118fc8a/coverage-7.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5afdad4cc4cc199fdf3e18088812edcf8f4c5a3c8e6cb69127513ad4cb7471a9"}, + {url = "https://files.pythonhosted.org/packages/85/e3/377befb686b7ebe288ef084c2822db81722681fab3774e389d026ea2d7ca/coverage-7.2.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ac0f522c3b6109c4b764ffec71bf04ebc0523e926ca7cbe6c5ac88f84faced0"}, + {url = "https://files.pythonhosted.org/packages/8c/c8/efee5b6e98f1009ca92333884d17eb205acb7aad800dc9b2d91475aef2a4/coverage-7.2.2-cp311-cp311-win32.whl", hash = "sha256:55272f33da9a5d7cccd3774aeca7a01e500a614eaea2a77091e9be000ecd401d"}, + {url = "https://files.pythonhosted.org/packages/8d/a6/6b3aae5b60e1e2ad8feb807cc33c5d313511980c3ee5de4662384165cec9/coverage-7.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2926b8abedf750c2ecf5035c07515770944acf02e1c46ab08f6348d24c5f94d"}, + {url = "https://files.pythonhosted.org/packages/8e/7f/b5709cc511c226c01ee8da008b9737726d8c62bd88cb20ef93eb5c9d80c8/coverage-7.2.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8efb48fa743d1c1a65ee8787b5b552681610f06c40a40b7ef94a5b517d885c54"}, + {url = "https://files.pythonhosted.org/packages/91/57/629e70906739102dbd742bcd7484f5446dfaacbd6dc3f46f42a88a0677c5/coverage-7.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5764e1f7471cb8f64b8cda0554f3d4c4085ae4b417bfeab236799863703e5de2"}, + {url = "https://files.pythonhosted.org/packages/95/06/b0541156f46970339776c42dafe5d227710127025cb96e4bd3176422016f/coverage-7.2.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2199988e0bc8325d941b209f4fd1c6fa007024b1442c5576f1a32ca2e48941e6"}, + {url = "https://files.pythonhosted.org/packages/9f/f0/ca6217975c4d756cbf136abfab805b470424279b322f8c9f191c21898ee9/coverage-7.2.2-cp38-cp38-win32.whl", hash = "sha256:4f01911c010122f49a3e9bdc730eccc66f9b72bd410a3a9d3cb8448bb50d65d3"}, + {url = "https://files.pythonhosted.org/packages/a6/8c/8a5f4fb03c4e23c69192ac8452f3448d2a408d204e39605614d7956dafa0/coverage-7.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:817295f06eacdc8623dc4df7d8b49cea65925030d4e1e2a7c7218380c0072c25"}, + {url = "https://files.pythonhosted.org/packages/af/dc/3fe8388df88c8dfa3d5771b1f746ef5bc92f0c718a10fcef3600199d00f7/coverage-7.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c90e73bdecb7b0d1cea65a08cb41e9d672ac6d7995603d6465ed4914b98b9ad7"}, + {url = "https://files.pythonhosted.org/packages/c1/dc/ef3f63275d1046b910a474eedf8eb9fa3265c30b5fab1c1391ed6351e9d9/coverage-7.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3eb55b7b26389dd4f8ae911ba9bc8c027411163839dea4c8b8be54c4ee9ae10b"}, + {url = "https://files.pythonhosted.org/packages/c7/de/80032c5d6340a3a3b29920ade4e09e3f240cee8410b88173babb9e7012be/coverage-7.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d683d230b5774816e7d784d7ed8444f2a40e7a450e5720d58af593cb0b94a212"}, + {url = "https://files.pythonhosted.org/packages/ca/45/687fb10526b66642a479b8703cd5ea53030fc582e76e7236e7a6318fd660/coverage-7.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c99cb7c26a3039a8a4ee3ca1efdde471e61b4837108847fb7d5be7789ed8fd9"}, + {url = "https://files.pythonhosted.org/packages/cb/03/76ca85381dd6aea8b190ae0fa9e7e7c3964f72f65fc32ef0454e68df4611/coverage-7.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6146910231ece63facfc5984234ad1b06a36cecc9fd0c028e59ac7c9b18c38c6"}, + {url = "https://files.pythonhosted.org/packages/d0/94/fa6095cce802c11a53685c5267330caed7ef02e2fb99b9f9f1c892859259/coverage-7.2.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:006ed5582e9cbc8115d2e22d6d2144a0725db542f654d9d4fda86793832f873d"}, + {url = "https://files.pythonhosted.org/packages/d4/cd/ef9d489e9c943636193de07e5089d84252c611572865e50e475495528070/coverage-7.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:8dbe2647bf58d2c5a6c5bcc685f23b5f371909a5624e9f5cd51436d6a9f6c6ef"}, + {url = "https://files.pythonhosted.org/packages/d8/3f/9df4f173d6f43ff80a11720cc3a9f4fa12d14ab36a2fb1a1d83ce026dd37/coverage-7.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:0ce383d5f56d0729d2dd40e53fe3afeb8f2237244b0975e1427bfb2cf0d32bab"}, + {url = "https://files.pythonhosted.org/packages/d8/de/effbd360724a67b8e8f7f297c4cffdd5510161aeb4de08b08e1fc6fbbd49/coverage-7.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57b77b9099f172804e695a40ebaa374f79e4fb8b92f3e167f66facbf92e8e7f5"}, + {url = "https://files.pythonhosted.org/packages/d9/55/f45a1d08ad1299c5199f3cf1baaa02fcffe347fdec8ddacc484858700ef6/coverage-7.2.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d52f0a114b6a58305b11a5cdecd42b2e7f1ec77eb20e2b33969d702feafdd016"}, + {url = "https://files.pythonhosted.org/packages/e5/d4/d8ee18c995b806b3d0d38dc17ab5888de148244da5be8d3dfbd7cea6cd7e/coverage-7.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:299bc75cb2a41e6741b5e470b8c9fb78d931edbd0cd009c58e5c84de57c06731"}, + {url = "https://files.pythonhosted.org/packages/f5/6f/7811ed60d4088b6a54bb48d57b48f647e55c876ee9088e3fa123eb879673/coverage-7.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:92ebc1619650409da324d001b3a36f14f63644c7f0a588e331f3b0f67491f512"}, +] +"exceptiongroup 1.1.1" = [ + {url = "https://files.pythonhosted.org/packages/61/97/17ed81b7a8d24d8f69b62c0db37abbd8c0042d4b3fc429c73dab986e7483/exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, + {url = "https://files.pythonhosted.org/packages/cc/38/57f14ddc8e8baeddd8993a36fe57ce7b4ba174c35048b9a6d270bb01e833/exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, +] +"iniconfig 2.0.0" = [ + {url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, +] +"markdown-it-py 2.2.0" = [ + {url = "https://files.pythonhosted.org/packages/bf/25/2d88e8feee8e055d015343f9b86e370a1ccbec546f2865c98397aaef24af/markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"}, + {url = "https://files.pythonhosted.org/packages/e4/c0/59bd6d0571986f72899288a95d9d6178d0eebd70b6650f1bb3f0da90f8f7/markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"}, +] +"mdurl 0.1.2" = [ + {url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] +"mypy 1.1.1" = [ + {url = "https://files.pythonhosted.org/packages/2a/28/8485aad67750b3374443d28bad3eed947737cf425a640ea4be4ac70a7827/mypy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce61663faf7a8e5ec6f456857bfbcec2901fbdb3ad958b778403f63b9e606a1b"}, + {url = "https://files.pythonhosted.org/packages/30/da/808ceaf2bcf23a9e90156c7b11b41add8dd5a009ee48159ec820d04d97bd/mypy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9401e33814cec6aec8c03a9548e9385e0e228fc1b8b0a37b9ea21038e64cdd8a"}, + {url = "https://files.pythonhosted.org/packages/44/9d/d23fa5d12bacbe7beea5fb6315b3325beabbe438e7e14d38c82b71609818/mypy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39c7119335be05630611ee798cc982623b9e8f0cff04a0b48dfc26100e0b97af"}, + {url = "https://files.pythonhosted.org/packages/47/9f/34f6a2254f7d39b8c4349b8ac480c233d37c377faf2c67c6ef925b3af0ab/mypy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:59bbd71e5c58eed2e992ce6523180e03c221dcd92b52f0e792f291d67b15a71c"}, + {url = "https://files.pythonhosted.org/packages/61/99/4a844dcacbc4990a8312236bf74a55910ee9a05db69dee7d6fb7a7ffe6c2/mypy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb19c9f662e41e474e0cff502b7064a7edc6764f5262b6cd91d698163196799"}, + {url = "https://files.pythonhosted.org/packages/62/54/be80f8d01f5cf72f774a77f9f750527a6fa733f09f78b1da30e8fa3914e6/mypy-1.1.1.tar.gz", hash = "sha256:ae9ceae0f5b9059f33dbc62dea087e942c0ccab4b7a003719cb70f9b8abfa32f"}, + {url = "https://files.pythonhosted.org/packages/64/63/6a04ca7a8b7f34811cada43ed6119736a7f4a07c5e1cbd8eec0e0f4962d5/mypy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d809f88734f44a0d44959d795b1e6f64b2bbe0ea4d9cc4776aa588bb4229fc1c"}, + {url = "https://files.pythonhosted.org/packages/65/cc/ae5032abc06949e7a8c68f9885883fdb745c96bcf137cd4fa7225d50b647/mypy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2888ce4fe5aae5a673386fa232473014056967f3904f5abfcf6367b5af1f612a"}, + {url = "https://files.pythonhosted.org/packages/67/d3/1323311369eae97da4c7f47f266c55f7bdc22e74e4e2e1691be511ab8a91/mypy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:69b35d1dcb5707382810765ed34da9db47e7f95b3528334a3c999b0c90fe523f"}, + {url = "https://files.pythonhosted.org/packages/7e/32/1b161731d19580c55d3d7c04b8ace80dc7cf42d852adf750f348a485068f/mypy-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b7c7b708fe9a871a96626d61912e3f4ddd365bf7f39128362bc50cbd74a634d5"}, + {url = "https://files.pythonhosted.org/packages/8a/fd/b610256224e01da4c4f315d11f62d39d815e97439a58d49d60aa4f55a60b/mypy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61bf08362e93b6b12fad3eab68c4ea903a077b87c90ac06c11e3d7a09b56b9c1"}, + {url = "https://files.pythonhosted.org/packages/8c/3d/a8d518bb06952484ada20897878a7a14741536f43514dcfecfac0676aa01/mypy-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c10fa12df1232c936830839e2e935d090fc9ee315744ac33b8a32216b93707"}, + {url = "https://files.pythonhosted.org/packages/91/63/55d0e62829f739f47978f1d8eb965ca8c40261841e47491ad297c84921c5/mypy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5cb14ff9919b7df3538590fc4d4c49a0f84392237cbf5f7a816b4161c061829e"}, + {url = "https://files.pythonhosted.org/packages/a4/0b/3a30f50287e42a4230320fa2eac25eb3017d38a7c31f083d407ab627607c/mypy-1.1.1-py3-none-any.whl", hash = "sha256:4e4e8b362cdf99ba00c2b218036002bdcdf1e0de085cdb296a49df03fb31dfc4"}, + {url = "https://files.pythonhosted.org/packages/b8/06/3d72d1b316ceec347874c4285fad8bf17e3fb21bb7848c1a942df239e44a/mypy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d64c28e03ce40d5303450f547e07418c64c241669ab20610f273c9e6290b4b0b"}, + {url = "https://files.pythonhosted.org/packages/b8/72/385f3aeaaf262325454ac7f569eb81ac623464871df23d9778c864d04c6c/mypy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:19ba15f9627a5723e522d007fe708007bae52b93faab00f95d72f03e1afa9598"}, + {url = "https://files.pythonhosted.org/packages/b9/e5/71eef5239219ee2f4d85e2ca6368d736705a3b874023b57f7237b977839c/mypy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b5f81b40d94c785f288948c16e1f2da37203c6006546c5d947aab6f90aefef2"}, + {url = "https://files.pythonhosted.org/packages/be/d5/5588a2ee0d77189626a57b555b6b006dda6d5b0083f16c6be0c2d761cd7b/mypy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b398d8b1f4fba0e3c6463e02f8ad3346f71956b92287af22c9b12c3ec965a9f"}, + {url = "https://files.pythonhosted.org/packages/bf/2d/45a526f248719ee32ecf1261564247a2e717a9c6167de5eb67d53599c4df/mypy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b437be1c02712a605591e1ed1d858aba681757a1e55fe678a15c2244cd68a5"}, + {url = "https://files.pythonhosted.org/packages/c0/d6/17ba6f8749722b8f61c6ab680769658f0bc63c293556149e2bf400b1f1a2/mypy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:315ac73cc1cce4771c27d426b7ea558fb4e2836f89cb0296cbe056894e3a1f78"}, + {url = "https://files.pythonhosted.org/packages/d3/35/a0892864f1c128dc6449ee69897f9db7a64de2c16f41c14640dd22251b1b/mypy-1.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0a28a76785bf57655a8ea5eb0540a15b0e781c807b5aa798bd463779988fa1d5"}, + {url = "https://files.pythonhosted.org/packages/d9/ab/d6d3884c3f432898458e2ade712988a7d1da562c1a363f2003b31677acd8/mypy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26cdd6a22b9b40b2fd71881a8a4f34b4d7914c679f154f43385ca878a8297389"}, + {url = "https://files.pythonhosted.org/packages/e1/a6/331cff5f7476904a2ebe6ed7cee2310b6be583ff6d45609ea0e0d67fd39d/mypy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64cc3afb3e9e71a79d06e3ed24bb508a6d66f782aff7e56f628bf35ba2e0ba51"}, + {url = "https://files.pythonhosted.org/packages/ed/89/85a04f32135fe4e35fd59d47100c939c7425fcb29868894c4b7a6171e065/mypy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:a380c041db500e1410bb5b16b3c1c35e61e773a5c3517926b81dfdab7582be54"}, + {url = "https://files.pythonhosted.org/packages/f5/35/da01ef5831ceaf99a673e018d06ff1622ec460e4164b5e900ddaeceb52e1/mypy-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ef6a01e563ec6a4940784c574d33f6ac1943864634517984471642908b30b6f7"}, + {url = "https://files.pythonhosted.org/packages/f6/57/93e676773f91141127329a56e2238eac506a78f6fb0ae0650a53fcc1355d/mypy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b0c373d071593deefbcdd87ec8db91ea13bd8f1328d44947e88beae21e8d5e9"}, +] +"mypy-extensions 1.0.0" = [ + {url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] +"nodeenv 1.7.0" = [ + {url = "https://files.pythonhosted.org/packages/96/a8/d3b5baead78adadacb99e7281b3e842126da825cf53df61688cfc8b8ff91/nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {url = "https://files.pythonhosted.org/packages/f3/9d/a28ecbd1721cd6c0ea65da6bfb2771d31c5d7e32d916a8f643b062530af3/nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, +] +"packaging 23.0" = [ + {url = "https://files.pythonhosted.org/packages/47/d5/aca8ff6f49aa5565df1c826e7bf5e85a6df852ee063600c1efa5b932968c/packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {url = "https://files.pythonhosted.org/packages/ed/35/a31aed2993e398f6b09a790a181a7927eb14610ee8bbf02dc14d31677f1c/packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, +] +"parse 1.19.0" = [ + {url = "https://files.pythonhosted.org/packages/89/a1/82ce536be577ba09d4dcee45db58423a180873ad38a2d014d26ab7b7cb8a/parse-1.19.0.tar.gz", hash = "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b"}, +] +"pathspec 0.11.1" = [ + {url = "https://files.pythonhosted.org/packages/95/60/d93628975242cc515ab2b8f5b2fc831d8be2eff32f5a1be4776d49305d13/pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, + {url = "https://files.pythonhosted.org/packages/be/c8/551a803a6ebb174ec1c124e68b449b98a0961f0b737def601e3c1fbb4cfd/pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, +] +"pendulum 2.1.2" = [ + {url = "https://files.pythonhosted.org/packages/2e/fb/32f72dfc7124fa311493607cd5d37438b0f0013bd40b27a44cd5606b35f6/pendulum-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:33fb61601083f3eb1d15edeb45274f73c63b3c44a8524703dc143f4212bf3269"}, + {url = "https://files.pythonhosted.org/packages/2f/df/dc70182a5857819210711d17b343391dd2db84d0a8d756797972364608d1/pendulum-2.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:318f72f62e8e23cd6660dbafe1e346950281a9aed144b5c596b2ddabc1d19739"}, + {url = "https://files.pythonhosted.org/packages/3e/40/bcf73cf69ffc4d68b80b68b5ce4e5f9d8185170e9fac65a73e247e948ff3/pendulum-2.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1245cd0075a3c6d889f581f6325dd8404aca5884dea7223a5566c38aab94642b"}, + {url = "https://files.pythonhosted.org/packages/3e/f8/f7a2d67c65c6bfd53fbb1abd856c395c22cf991b92ea77a35af88f7e96b2/pendulum-2.1.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f5e236e7730cab1644e1b87aca3d2ff3e375a608542e90fe25685dae46310116"}, + {url = "https://files.pythonhosted.org/packages/48/1c/dbca87b468531618c215bb5c5f438fa98ad9213f50f76bbb14836a7c0d4e/pendulum-2.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c807a578a532eeb226150d5006f156632df2cc8c5693d778324b43ff8c515dd0"}, + {url = "https://files.pythonhosted.org/packages/5d/d0/75835105fb4951b5195bbaa3b9797c258bbf9aa211c6f26b26a68ebf6cee/pendulum-2.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7c5ec650cb4bec4c63a89a0242cc8c3cebcec92fcfe937c417ba18277d8560be"}, + {url = "https://files.pythonhosted.org/packages/64/c9/96ebff288bba66c049398404491a3d1abe9446e5501e78aa5473589ebb5e/pendulum-2.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4c9c689747f39d0d02a9f94fcee737b34a5773803a64a5fdb046ee9cac7442c5"}, + {url = "https://files.pythonhosted.org/packages/6f/d0/3b9ebd15ae3d4e079d6174ee49b19c113189558d3c5e1e641d03bc4560d2/pendulum-2.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2d1619a721df661e506eff8db8614016f0720ac171fe80dda1333ee44e684087"}, + {url = "https://files.pythonhosted.org/packages/7d/09/47ce955fbd41b2930430a78c744c903b79e552c54fb38a3283d7640454fd/pendulum-2.1.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:c501749fdd3d6f9e726086bf0cd4437281ed47e7bca132ddb522f86a1645d360"}, + {url = "https://files.pythonhosted.org/packages/8e/4b/b2042f5122a4b3508c736304e38e8b41e2feed9f3d8c08a03d1de10a2a2b/pendulum-2.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:94b1fc947bfe38579b28e1cccb36f7e28a15e841f30384b5ad6c5e31055c85d7"}, + {url = "https://files.pythonhosted.org/packages/95/13/e7598039a7c2be1c74538125c035f866189897291f12da029a2a1008dc3e/pendulum-2.1.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:b6c352f4bd32dff1ea7066bd31ad0f71f8d8100b9ff709fb343f3b86cee43efe"}, + {url = "https://files.pythonhosted.org/packages/a2/90/3020eeb52dd3c6c01eb5009304c6947dfb08daf46eb29c3a33a5ea5fbccd/pendulum-2.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:de42ea3e2943171a9e95141f2eecf972480636e8e484ccffaf1e833929e9e052"}, + {url = "https://files.pythonhosted.org/packages/bd/c9/e8ca81966ba87f977ca5fba8822be2e96848d079e5afcc38e538234301a0/pendulum-2.1.2-cp35-cp35m-macosx_10_15_x86_64.whl", hash = "sha256:0731f0c661a3cb779d398803655494893c9f581f6488048b3fb629c2342b5394"}, + {url = "https://files.pythonhosted.org/packages/c0/09/8e7c65e347e71baf8dfd799f03983f22eeb4d591e10e90da026037ddad64/pendulum-2.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f888f2d2909a414680a29ae74d0592758f2b9fcdee3549887779cd4055e975db"}, + {url = "https://files.pythonhosted.org/packages/cd/15/3ee08d358a88f9a871b2ef8b25896f9bc6b6fe4d05fb5587c5c9e29950dc/pendulum-2.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:fb53ffa0085002ddd43b6ca61a7b34f2d4d7c3ed66f931fe599e1a531b42af9b"}, + {url = "https://files.pythonhosted.org/packages/d0/21/284171c69ef27d1173e8997ec73c5551f9491459b48003b64d191a0c7082/pendulum-2.1.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e95d329384717c7bf627bf27e204bc3b15c8238fa8d9d9781d93712776c14002"}, + {url = "https://files.pythonhosted.org/packages/d4/75/f1faafe184d6fa15a7f983165b2fa495a721ff04a92c08199a9f5399b4d4/pendulum-2.1.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:3481fad1dc3f6f6738bd575a951d3c15d4b4ce7c82dce37cf8ac1483fde6e8b0"}, + {url = "https://files.pythonhosted.org/packages/db/15/6e89ae7cde7907118769ed3d2481566d05b5fd362724025198bb95faf599/pendulum-2.1.2.tar.gz", hash = "sha256:b06a0ca1bfe41c990bbf0c029f0b6501a7f2ec4e38bfec730712015e8860f207"}, + {url = "https://files.pythonhosted.org/packages/e2/d9/909cab9450467aeae5aea140ac108624b1aa1d40446050e96f394a95e0ab/pendulum-2.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9702069c694306297ed362ce7e3c1ef8404ac8ede39f9b28b7c1a7ad8c3959e3"}, + {url = "https://files.pythonhosted.org/packages/e3/30/e695237aa47fda242a1ca7b3bcb75ae0cd9588a2cf94737eb5b0dc4caa8f/pendulum-2.1.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:29c40a6f2942376185728c9a0347d7c0f07905638c83007e1d262781f1e6953a"}, + {url = "https://files.pythonhosted.org/packages/f6/fa/fcddef6138ced8b676e50f1f7d66ea9081b647810b86d52b29e1a653b9a1/pendulum-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:db0a40d8bcd27b4fb46676e8eb3c732c67a5a5e6bfab8927028224fbced0b40b"}, +] +"platformdirs 3.2.0" = [ + {url = "https://files.pythonhosted.org/packages/15/04/3f882b46b454ab374ea75425c6f931e499150ec1385a73e55b3f45af615a/platformdirs-3.2.0.tar.gz", hash = "sha256:d5b638ca397f25f979350ff789db335903d7ea010ab28903f57b27e1b16c2b08"}, + {url = "https://files.pythonhosted.org/packages/b2/f3/4fb5fae710fc9f22a42cd90dc0547da18ec83e2e139294ab94f04c449cf5/platformdirs-3.2.0-py3-none-any.whl", hash = "sha256:ebe11c0d7a805086e99506aa331612429a72ca7cd52a1f0d277dc4adc20cb10e"}, +] +"pluggy 1.0.0" = [ + {url = "https://files.pythonhosted.org/packages/9e/01/f38e2ff29715251cf25532b9082a1589ab7e4f571ced434f98d0139336dc/pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {url = "https://files.pythonhosted.org/packages/a1/16/db2d7de3474b6e37cbb9c008965ee63835bba517e22cdb8c35b5116b5ce1/pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +"pprintpp 0.4.0" = [ + {url = "https://files.pythonhosted.org/packages/06/1a/7737e7a0774da3c3824d654993cf57adc915cb04660212f03406334d8c0b/pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"}, + {url = "https://files.pythonhosted.org/packages/4e/d1/e4ed95fdd3ef13b78630280d9e9e240aeb65cc7c544ec57106149c3942fb/pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"}, +] +"pydantic 1.10.7" = [ + {url = "https://files.pythonhosted.org/packages/00/43/f15d991ce715a2e7a229ef7c2534527d6fe4e5d260a675bd06615a4ede82/pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"}, + {url = "https://files.pythonhosted.org/packages/05/4e/92a0c1fd305f764801dba26182b08ccf72026766fc4451d88186185467f2/pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"}, + {url = "https://files.pythonhosted.org/packages/07/3a/5bc906697c9aa0f0fc28f81ec25995315c999fb6df7b29e56a49b08009a3/pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"}, + {url = "https://files.pythonhosted.org/packages/14/60/08f4b0a87561f64305002dffc5db2078043d46ed213e730a92e16840b120/pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"}, + {url = "https://files.pythonhosted.org/packages/21/ab/d7d0f74be71041507fe7ab1a61a71b251fc7667e720323b1f51a039370bb/pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"}, + {url = "https://files.pythonhosted.org/packages/2e/97/e1e06d17f0f928083c660f6750b321797371ebd43aa16eda0ae80a4d3a7c/pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"}, + {url = "https://files.pythonhosted.org/packages/31/9e/32896df239096e0052e390e90eb0d374367e74bf7ce603a62841310c34c7/pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"}, + {url = "https://files.pythonhosted.org/packages/34/d8/fd31b8172643cbf2cfd42398cba1406ea47ca1268f5e7ba48227f06c61a6/pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"}, + {url = "https://files.pythonhosted.org/packages/38/cb/21afb81e5b3270cf5504543fb94a0d7734c4536b98c893701842602f9da0/pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"}, + {url = "https://files.pythonhosted.org/packages/42/dc/092da33080729a95805e73084abf7cc064de7ae64462d1081859b2c1b7e2/pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"}, + {url = "https://files.pythonhosted.org/packages/43/5f/e53a850fd32dddefc998b6bfcbda843d4ff5b0dcac02a92e414ba6c97d46/pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"}, + {url = "https://files.pythonhosted.org/packages/5e/06/a6b6a325b4085558d48f8804433b523bf31b62e8bcad6a9f8537418240d6/pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"}, + {url = "https://files.pythonhosted.org/packages/67/a9/f4fde01bb028c2afd0bd053ba440f7aeb609a9dc85f5d2d41a937526dbe8/pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"}, + {url = "https://files.pythonhosted.org/packages/67/ac/ff5f7eca22bf58dbecfd266597e15b1ec7ddc68b886157a2095a25eedb17/pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"}, + {url = "https://files.pythonhosted.org/packages/73/f9/860473019e228ac0b12e5cccecc086ce1f7e41d5f1482b64b9454a528e4f/pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"}, + {url = "https://files.pythonhosted.org/packages/7e/2f/05c7f8dbd1de1542d7560b5e7b5aeb7d58558af2262010f8de9abb466be1/pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"}, + {url = "https://files.pythonhosted.org/packages/81/1b/04ce5303aee97af30b94c45699ed228b8ba6ba64c972efac184fb9a566f3/pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"}, + {url = "https://files.pythonhosted.org/packages/83/f2/b86db67c476177ec73fce0ea87e3fa0fd686c0602efbd4e42e5ccdb2bab9/pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"}, + {url = "https://files.pythonhosted.org/packages/8a/64/db1aafc37fab0dad89e0a27f120a18f2316fca704e9f95096ade47b933ac/pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"}, + {url = "https://files.pythonhosted.org/packages/8a/9b/4a6e7f721e54269966be968b7672f23b69d396ff59af7be6ea2e7bc30d0b/pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"}, + {url = "https://files.pythonhosted.org/packages/8d/e1/d9219c4e4161a511158e531a84aa719087064d208c2bf87df5c58812f190/pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"}, + {url = "https://files.pythonhosted.org/packages/91/b8/e02d21709db955b92125059d6f80a1a543f9cc9f60ef212621514462b4e9/pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"}, + {url = "https://files.pythonhosted.org/packages/a0/ef/9b9a6c4f2e520c84c86908105bdec18a06449be0b2ec5c73526eba141402/pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"}, + {url = "https://files.pythonhosted.org/packages/a4/cb/16648745548e4c18f4b98b7e323bbac698e77cd8fc250a6b2ff83688c95f/pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"}, + {url = "https://files.pythonhosted.org/packages/aa/64/1b66f84ffe07562366c5ae87e83f0b3871afefd97f0632091629e6d5cfb2/pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"}, + {url = "https://files.pythonhosted.org/packages/b8/b7/158fb5bf629f5a97c997711757fb14e831825872c6d091a41a769c9c69e4/pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"}, + {url = "https://files.pythonhosted.org/packages/c8/70/8fe094a67a9431095069f6f9eb2a893e11fdaec8c1182016f53a535adfec/pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"}, + {url = "https://files.pythonhosted.org/packages/c8/f3/8b3d444bdce482d6c206ab2b3ad309ae699f3074fde3d5e54c786f22b8c0/pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"}, + {url = "https://files.pythonhosted.org/packages/d1/a1/0aa23b545299186f6eabc7a5d289a951e6c033852938ae6673d75846e611/pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"}, + {url = "https://files.pythonhosted.org/packages/d5/f0/a1bab22b297fc4333d496b34e0db42bc33c85c4b0e7e7a39da76fc65a643/pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"}, + {url = "https://files.pythonhosted.org/packages/d6/59/8082b963e077ea4bec5bb85e8c0fc636e4e7b3484e6a8ceac94e743e3b74/pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"}, + {url = "https://files.pythonhosted.org/packages/dc/01/03bb09fdb5c06075c5dc79d4c68885e87fdc7e8becf347d6a1ff8f890f79/pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"}, + {url = "https://files.pythonhosted.org/packages/f1/bd/0dad4908e5f693b7951b68f435139ec583f5eebb3d75505e1efa0f2284fe/pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"}, + {url = "https://files.pythonhosted.org/packages/f6/2d/0fc591686bc119d844f26268f503a7a504fbc9dd6a02e14aa42738c21fed/pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"}, + {url = "https://files.pythonhosted.org/packages/fa/c2/3df79cd00e65678fce12e59e8c95378a992a93d7b9f9510d4f1f65df1936/pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, + {url = "https://files.pythonhosted.org/packages/fd/66/3da2e7c0306251435bd61ae9da52db8a00672fdf2b2db1e3efe1692f41dd/pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, +] +"pyfakefs 5.1.0" = [ + {url = "https://files.pythonhosted.org/packages/38/4b/0e12c26797eeb1ea4574f3b94937817ee781a13d3fb800c2dc4c115a56f3/pyfakefs-5.1.0.tar.gz", hash = "sha256:316c6026640d14a6b4fbde71fd9674576d1b5710deda8fabde8aad51d785dbc3"}, + {url = "https://files.pythonhosted.org/packages/a4/db/1b738a4d422eee1bb9688c2ea01d9b4bcc02e4e98ad71e13f5db3ff3cd5a/pyfakefs-5.1.0-py3-none-any.whl", hash = "sha256:e6f34a8224b41f1b1ab25aa8d430121dac42e3c6e981e01eae76b3343fba47d0"}, +] +"pygments 2.14.0" = [ + {url = "https://files.pythonhosted.org/packages/0b/42/d9d95cc461f098f204cd20c85642ae40fbff81f74c300341b8d0e0df14e0/Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, + {url = "https://files.pythonhosted.org/packages/da/6a/c427c06913204e24de28de5300d3f0e809933f376e0b7df95194b2bb3f71/Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, +] +"pyrage 1.0.3" = [ + {url = "https://files.pythonhosted.org/packages/60/c6/d96e0d8b8829030dca1523ccb269758c6b558ddee58daf88d3bb26bfcf95/pyrage-1.0.3-cp37-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:37a8c1555f51b419a73759ce925f643e789802bba7bed5bbfbe11e99be610d49"}, + {url = "https://files.pythonhosted.org/packages/d9/a4/785af8296a882132b63de046c54d9a45c8d1d634e22c5d40463accd8eefd/pyrage-1.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c554d7669539c0a7a870464faf55f0121c117339b1b0f57d6ca5eb85079c107"}, + {url = "https://files.pythonhosted.org/packages/fb/9c/54a5c8aad8442ba26845c325c8b4eaa90cc3b470d0e57465d82ca54ad843/pyrage-1.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:32b63a06f138a1c231285c61f61a1800b7b894851b06cb763b7b35b18ccd2b11"}, +] +"pyrage-stubs 1.0.1" = [ + {url = "https://files.pythonhosted.org/packages/00/5c/5e0430c00a0094d7e86b3487839de6b4213cf34f46faf27cc98acac54084/pyrage_stubs-1.0.1-py3-none-any.whl", hash = "sha256:729d9c8ac43f9aac9e22fe6ae3cf285a4f0740bece7b793a57eb229fb6db93a7"}, + {url = "https://files.pythonhosted.org/packages/6f/c3/352df4e5927d4f34fefdd0e9e0332061c3b98937e39b871c91f8e66098ea/pyrage-stubs-1.0.1.tar.gz", hash = "sha256:e33bc444bfda7b5a783d3821aa99ba9269d2a9f2c39ccd8aba46a7b8525fbd22"}, +] +"pyright 1.1.301" = [ + {url = "https://files.pythonhosted.org/packages/1f/f9/35360780b41236428be6a2a8f8f53007d5460e757d8bfe007b7303f63682/pyright-1.1.301.tar.gz", hash = "sha256:6ac4afc0004dca3a977a4a04a8ba25b5b5aa55f8289550697bfc20e11be0d5f2"}, + {url = "https://files.pythonhosted.org/packages/4c/af/7a7bd8513361934d269aca00bdea5f879d92e5b89f79e4923d1f1b06d498/pyright-1.1.301-py3-none-any.whl", hash = "sha256:ecc3752ba8c866a8041c90becf6be79bd52f4c51f98472e4776cae6d55e12826"}, +] +"pytest 7.2.2" = [ + {url = "https://files.pythonhosted.org/packages/b2/68/5321b5793bd506961bd40bdbdd0674e7de4fb873ee7cab33dd27283ad513/pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"}, + {url = "https://files.pythonhosted.org/packages/b9/29/311895d9cd3f003dd58e8fdea36dd895ba2da5c0c90601836f7de79f76fe/pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"}, +] +"pytest-clarity 1.0.1" = [ + {url = "https://files.pythonhosted.org/packages/52/5c/cafa97944de55738a6a2c5a7cee00d073cb80495032d2b112c4546525eca/pytest-clarity-1.0.1.tar.gz", hash = "sha256:505fe345fad4fe11c6a4187fe683f2c7c52c077caa1e135f3e483fe112db7772"}, +] +"pytest-cov 4.0.0" = [ + {url = "https://files.pythonhosted.org/packages/ea/70/da97fd5f6270c7d2ce07559a19e5bf36a76f0af21500256f005a69d9beba/pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {url = "https://files.pythonhosted.org/packages/fe/1f/9ec0ddd33bd2b37d6ec50bb39155bca4fe7085fa78b3b434c05459a860e3/pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] +"pytest-duration-insights 0.1.1" = [ + {url = "https://files.pythonhosted.org/packages/07/e1/5f71f28d1f77ade128b54c20cee04e34508f7480f599d418baf26547c64e/pytest_duration_insights-0.1.1-py2.py3-none-any.whl", hash = "sha256:27f771077f58b558a62fee0af396c1a2efc4aa1217aad9e0cf11d120b2067e86"}, + {url = "https://files.pythonhosted.org/packages/cf/09/b2129ad0ff70f0283d86e76497ddac9b53f0aa876fec8462dc3408d3721d/pytest-duration-insights-0.1.1.tar.gz", hash = "sha256:9dcc6aca40bfbdab2b0b34f0e55c3b5bd4ac41f3a419a2b7b8a22fb7ebe62933"}, +] +"pytest-pretty 1.1.1" = [ + {url = "https://files.pythonhosted.org/packages/ba/8f/7cafa3856d81175264fcc8929d0c5c60e59b787b1b2891095b77a7aaebb7/pytest_pretty-1.1.1.tar.gz", hash = "sha256:dfabbeee334ff5e77f3f731623cd44f147b3db7001df8d9ef8ea1f54986b41e2"}, + {url = "https://files.pythonhosted.org/packages/c5/98/859ccc1482b23c008e434da91880bb1197e29d9fe3644c3124b58e9b6bd9/pytest_pretty-1.1.1-py3-none-any.whl", hash = "sha256:22d19d319f2ce07d62ea64f487616d99433cae8530cd20813487bad8a7d5f088"}, +] +"pytest-reportlog 0.2.1" = [ + {url = "https://files.pythonhosted.org/packages/41/9a/6898175d1079b888994f25388afe7ffa0704a36d5549dd0e1143b01bfba2/pytest-reportlog-0.2.1.tar.gz", hash = "sha256:df59f7f1fcd9a0388e39b30e5aa264a609e64953e116f3ea6eb3aab22e3658e6"}, + {url = "https://files.pythonhosted.org/packages/69/d9/636a707bfb67df041dac191abdb5412db4a25167c057a9d5bdcc60f56669/pytest_reportlog-0.2.1-py3-none-any.whl", hash = "sha256:65ac38cb5af90470df3dde6c03a6dd88090913d16765ee54d135279b5579c113"}, +] +"python-dateutil 2.8.2" = [ + {url = "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {url = "https://files.pythonhosted.org/packages/4c/c4/13b4776ea2d76c115c1d1b84579f3764ee6d57204f6be27119f13a61d0a9/python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, +] +"pytzdata 2020.1" = [ + {url = "https://files.pythonhosted.org/packages/67/62/4c25435a7c2f9c7aef6800862d6c227fc4cd81e9f0beebc5549a49c8ed53/pytzdata-2020.1.tar.gz", hash = "sha256:3efa13b335a00a8de1d345ae41ec78dd11c9f8807f522d39850f2dd828681540"}, + {url = "https://files.pythonhosted.org/packages/e0/4f/4474bda990ee740a020cbc3eb271925ef7daa7c8444240d34ff62c8442a3/pytzdata-2020.1-py2.py3-none-any.whl", hash = "sha256:e1e14750bcf95016381e4d472bad004eef710f2d6417240904070b3d6654485f"}, +] +"pyyaml 6.0" = [ + {url = "https://files.pythonhosted.org/packages/02/25/6ba9f6bb50a3d4fbe22c1a02554dc670682a07c8701d1716d19ddea2c940/PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {url = "https://files.pythonhosted.org/packages/08/f4/ffa743f860f34a5e8c60abaaa686f82c9ac7a2b50e5a1c3b1eb564d59159/PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {url = "https://files.pythonhosted.org/packages/0f/93/5f81d1925ce3b531f5ff215376445ec220887cd1c9a8bde23759554dbdfd/PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {url = "https://files.pythonhosted.org/packages/12/fc/a4d5a7554e0067677823f7265cb3ae22aed8a238560b5133b58cda252dad/PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {url = "https://files.pythonhosted.org/packages/21/67/b42191239c5650c9e419c4a08a7a022bbf1abf55b0391c380a72c3af5462/PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {url = "https://files.pythonhosted.org/packages/2e/b3/13dfd4eeb5e4b2d686b6d1822b40702e991bf3a4194ca5cbcce8d43749db/PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {url = "https://files.pythonhosted.org/packages/36/2b/61d51a2c4f25ef062ae3f74576b01638bebad5e045f747ff12643df63844/PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, + {url = "https://files.pythonhosted.org/packages/44/e5/4fea13230bcebf24b28c0efd774a2dd65a0937a2d39e94a4503438b078ed/PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {url = "https://files.pythonhosted.org/packages/4d/7d/c2ab8da648cd2b937de11fb35649b127adab4851cbeaf5fd9b60a2dab0f7/PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {url = "https://files.pythonhosted.org/packages/55/e3/507a92589994a5b3c3d7f2a7a066339d6ff61c5c839bae56f7eff03d9c7b/PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {url = "https://files.pythonhosted.org/packages/56/8f/e8b49ad21d26111493dc2d5cae4d7efbd0e2e065440665f5023515f87f64/PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {url = "https://files.pythonhosted.org/packages/59/00/30e33fcd2a4562cd40c49c7740881009240c5cbbc0e41ca79ca4bba7c24b/PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {url = "https://files.pythonhosted.org/packages/5e/f4/7b4bb01873be78fc9fde307f38f62e380b7111862c165372cf094ca2b093/PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {url = "https://files.pythonhosted.org/packages/63/6b/f5dc7942bac17192f4ef00b2d0cdd1ae45eea453d05c1944c0573debe945/PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {url = "https://files.pythonhosted.org/packages/67/d4/b95266228a25ef5bd70984c08b4efce2c035a4baa5ccafa827b266e3dc36/PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {url = "https://files.pythonhosted.org/packages/68/3f/c027422e49433239267c62323fbc6320d6ac8d7d50cf0cb2a376260dad5f/PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {url = "https://files.pythonhosted.org/packages/6c/3d/524c642f3db37e7e7ab8d13a3f8b0c72d04a619abc19100097d987378fc6/PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {url = "https://files.pythonhosted.org/packages/74/68/3c13deaa496c14a030c431b7b828d6b343f79eb241b4848c7918091a64a2/PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {url = "https://files.pythonhosted.org/packages/77/da/e845437ffe0dffae4e7562faf23a4f264d886431c5d2a2816c853288dc8e/PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {url = "https://files.pythonhosted.org/packages/7f/d9/6a0d14ac8d3b5605dc925d177c1d21ee9f0b7b39287799db1e50d197b2f4/PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {url = "https://files.pythonhosted.org/packages/81/59/561f7e46916b78f3c4cab8d0c307c81656f11e32c846c0c97fda0019ed76/PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {url = "https://files.pythonhosted.org/packages/89/26/0bfd7b756b34c68f8fd158b7bc762b6b1705fc1b3cebf4cdbb53fd9ea75b/PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {url = "https://files.pythonhosted.org/packages/91/49/d46d7b15cddfa98533e89f3832f391aedf7e31f37b4d4df3a7a7855a7073/PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {url = "https://files.pythonhosted.org/packages/9d/f6/7e91fbb58c9ee528759aea5892e062cccb426720c5830ddcce92eba00ff1/PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {url = "https://files.pythonhosted.org/packages/a4/ba/e508fc780e3c94c12753a54fe8f74de535741a10d33b29a576a9bec03500/PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {url = "https://files.pythonhosted.org/packages/a4/e6/4d7a01bc0730c8f958a62d6a4c4f3df23b6139ad68c132b168970d84f192/PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {url = "https://files.pythonhosted.org/packages/a8/32/1bbe38477fb23f1d83041fefeabf93ef1cd6f0efcf44c221519507315d92/PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {url = "https://files.pythonhosted.org/packages/a8/5b/c4d674846ea4b07ee239fbf6010bcc427c4e4552ba5655b446e36b9a40a7/PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {url = "https://files.pythonhosted.org/packages/b3/85/79b9e5b4e8d3c0ac657f4e8617713cca8408f6cdc65d2ee6554217cedff1/PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {url = "https://files.pythonhosted.org/packages/b7/09/2f6f4851bbca08642fef087bade095edc3c47f28d1e7bff6b20de5262a77/PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {url = "https://files.pythonhosted.org/packages/cb/5f/05dd91f5046e2256e35d885f3b8f0f280148568f08e1bf20421887523e9a/PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {url = "https://files.pythonhosted.org/packages/d1/c0/4fe04181b0210ee2647cfbb89ecd10a36eef89f10d8aca6a192c201bbe58/PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {url = "https://files.pythonhosted.org/packages/d7/42/7ad4b6d67a16229496d4f6e74201bdbebcf4bc1e87d5a70c9297d4961bd2/PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {url = "https://files.pythonhosted.org/packages/db/4e/74bc723f2d22677387ab90cd9139e62874d14211be7172ed8c9f9a7c81a9/PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {url = "https://files.pythonhosted.org/packages/df/75/ee0565bbf65133e5b6ffa154db43544af96ea4c42439e6b58c1e0eb44b4e/PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {url = "https://files.pythonhosted.org/packages/eb/5f/6e6fe6904e1a9c67bc2ca5629a69e7a5a0b17f079da838bab98a1e548b25/PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {url = "https://files.pythonhosted.org/packages/ef/ad/b443cce94539e57e1a745a845f95c100ad7b97593d7e104051e43f730ecd/PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {url = "https://files.pythonhosted.org/packages/f5/6f/b8b4515346af7c33d3b07cd8ca8ea0700ca72e8d7a750b2b87ac0268ca4e/PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {url = "https://files.pythonhosted.org/packages/f8/54/799b059314b13e1063473f76e908f44106014d18f54b16c83a16edccd5ec/PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {url = "https://files.pythonhosted.org/packages/fc/48/531ecd926fe0a374346dd811bf1eda59a95583595bb80eadad511f3269b8/PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, +] +"rich 13.3.3" = [ + {url = "https://files.pythonhosted.org/packages/42/5c/f44fc88bad850c4a20711a3349ec0e8bc50fece8d8b32c962d2aab70ea2b/rich-13.3.3-py3-none-any.whl", hash = "sha256:540c7d6d26a1178e8e8b37e9ba44573a3cd1464ff6348b99ee7061b95d1c6333"}, + {url = "https://files.pythonhosted.org/packages/9a/50/672a8d347f92bc752b04c338bbf932fbd0104fbc416c82cc91aa5f7b4b0b/rich-13.3.3.tar.gz", hash = "sha256:dc84400a9d842b3a9c5ff74addd8eb798d155f36c1c91303888e0a66850d2a15"}, +] +"ruff 0.0.260" = [ + {url = "https://files.pythonhosted.org/packages/09/e0/3ba8f02041ac5a1b466364ff96abae4838f4852d56177a079075b35885d6/ruff-0.0.260-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57d9f0bfdef739b76aa3112b9182a214f0f34589a2659f88353492c7670fe2fe"}, + {url = "https://files.pythonhosted.org/packages/0e/1a/cde78a0c594a0a07adcc0f5b191587dd28e29524022502b92f0b8c0324bb/ruff-0.0.260-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4fa7293f97c021825b3b72f2bf53f0eb4f59625608a889678c1fc6660f412d"}, + {url = "https://files.pythonhosted.org/packages/14/d3/517080b9623d86aabc550d77cd118cc78156836894832917cf5a6d2ff89f/ruff-0.0.260-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8bec0271e2c8cd36bcf915cb9f6a93e40797a3ff3d2cda4ca87b7bed9e598472"}, + {url = "https://files.pythonhosted.org/packages/18/c0/c2c3efcddff1ec814bac21e06b6892e09b7304b710b163605a24002d4215/ruff-0.0.260-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e075a61aaff8ebe56172217f0ac14c5df9637b289bf161ac697445a9003d5c2"}, + {url = "https://files.pythonhosted.org/packages/42/b0/dab6b854f45b7709d21cbb9658fb5027a8ad0f594673f16691032be3fe03/ruff-0.0.260.tar.gz", hash = "sha256:ea8f94262f33b81c47ee9d81f455b144e94776f5c925748cb0c561a12206eae1"}, + {url = "https://files.pythonhosted.org/packages/6f/c5/6753f698c20ee047e0ccf37699c428cee27bdd686d66d7b7fbf0d8f64064/ruff-0.0.260-py3-none-win32.whl", hash = "sha256:3866a96b2ef92c7d837ba6bf8fc9dd125a67886f1c5512ad6fa5d5fefaceff87"}, + {url = "https://files.pythonhosted.org/packages/8a/97/9162045353f3c162e32a00a0cc6f8026600daac453939f256e04e9b81bcf/ruff-0.0.260-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25584d1b9f445fde72651caab97e7430a4c5bfd2a0ce9af39868753826cba10d"}, + {url = "https://files.pythonhosted.org/packages/90/01/e9b06ec57caa0c36a90ede26b86a8603f4eee61d0da4a2e5f597cc7f5c43/ruff-0.0.260-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:aae2170a7ec6f7fc4a73db30aa7aa7fce936176bf66bf85f77f69ddd1dd4a665"}, + {url = "https://files.pythonhosted.org/packages/93/54/fad086cfd66eaa611549da82f381a77e752c283e34c3548cd650ac27369e/ruff-0.0.260-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6dd705d4eff405c2b70513188fbff520f49db6df91f0d5e8258c5d469efa58bc"}, + {url = "https://files.pythonhosted.org/packages/9e/ba/ad56a4f7c7c9213e62ba50c6d6c24a1a35d184d40620876c8fa6848693e3/ruff-0.0.260-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:90ff1479e292a84c388a8a035d223247ddeea5f6760752a9142b88b6d59ac334"}, + {url = "https://files.pythonhosted.org/packages/a2/5d/261b7a1d795fe097c4b11dcd8336acce43ac4a3e73f0f7f86cc609fd8745/ruff-0.0.260-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f847b72ef994ab88e9da250c7eb5cbb3f1555b92a9f22c5ed1c27a44b7e98d6"}, + {url = "https://files.pythonhosted.org/packages/a3/89/78e78b2af514c2960a684a0b1deb4b8b21368541b7c82e18a2599002a443/ruff-0.0.260-py3-none-win_arm64.whl", hash = "sha256:12542a26f189a5a10c719bfa14d415d0511ac05e5c9ff5e79cc9d5cc50b81bc8"}, + {url = "https://files.pythonhosted.org/packages/b6/f2/d996c980b9eeb644d312376bf00e4831a04720f3bfd6fa3c474dc536a416/ruff-0.0.260-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8678f54eb2696481618902a10c3cb28325f3323799af99997ad6f06005ea4f5"}, + {url = "https://files.pythonhosted.org/packages/b9/f9/1b355d585b971a77687d6dc2cd680e7e5af66394a8c75a25ac73d8dd3243/ruff-0.0.260-py3-none-win_amd64.whl", hash = "sha256:0733d524946decbd4f1e63f7dc26820f5c1e6c31da529ba20fb995057f8e79b1"}, + {url = "https://files.pythonhosted.org/packages/c1/3e/cb041a9d5bd90173e8050c2740bde3080388604ea60b8e66348f52e6a72d/ruff-0.0.260-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:c559650b623f3fbdc39c7ed1bcb064765c666a53ee738c53d1461afbf3f23db2"}, + {url = "https://files.pythonhosted.org/packages/fc/ca/1c9fe9d576405cf5883c041c7693f2c8de828a7aa1b5dd80ea473f85b9bc/ruff-0.0.260-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ec1f77219ba5adaa194289cb82ba924ff2ed931fd00b8541d66a1724c89fbc9"}, + {url = "https://files.pythonhosted.org/packages/fe/ab/aa9d7d785b1bcc9e34cfe85e27a2e21a508bfce447856f876d6c3ccb294d/ruff-0.0.260-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8032e35357384a29791c75194a71e314031171eb0731fcaa872dfaf4c1f4470a"}, +] +"setuptools 67.6.1" = [ + {url = "https://files.pythonhosted.org/packages/0b/fc/8781442def77b0aa22f63f266d4dadd486ebc0c5371d6290caf4320da4b7/setuptools-67.6.1-py3-none-any.whl", hash = "sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078"}, + {url = "https://files.pythonhosted.org/packages/cb/46/22ec35f286a77e6b94adf81b4f0d59f402ed981d4251df0ba7b992299146/setuptools-67.6.1.tar.gz", hash = "sha256:257de92a9d50a60b8e22abfcbb771571fde0dbf3ec234463212027a4eeecbe9a"}, +] +"six 1.16.0" = [ + {url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, +] +"tomli 2.0.1" = [ + {url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {url = "https://files.pythonhosted.org/packages/c0/3f/d7af728f075fb08564c5949a9c95e44352e23dee646869fa104a3b2060a3/tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] +"typer 0.7.0" = [ + {url = "https://files.pythonhosted.org/packages/0d/44/56c3f48d2bb83d76f5c970aef8e2c3ebd6a832f09e3621c5395371fe6999/typer-0.7.0-py3-none-any.whl", hash = "sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d"}, + {url = "https://files.pythonhosted.org/packages/e1/45/bcbc581f87c8d8f2a56b513eb994d07ea4546322818d95dc6a3caf2c928b/typer-0.7.0.tar.gz", hash = "sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165"}, +] +"types-pyyaml 6.0.12.9" = [ + {url = "https://files.pythonhosted.org/packages/05/6f/f19081de5ba81864f89e354560a60637822f7d6d54d9a2a907785e9b5cc4/types-PyYAML-6.0.12.9.tar.gz", hash = "sha256:c51b1bd6d99ddf0aa2884a7a328810ebf70a4262c292195d3f4f9a0005f9eeb6"}, + {url = "https://files.pythonhosted.org/packages/88/93/a98be346729157d9f085fd68e58fcbba823188829ac8488a9d7f12614e53/types_PyYAML-6.0.12.9-py3-none-any.whl", hash = "sha256:5aed5aa66bd2d2e158f75dda22b059570ede988559f030cf294871d3b647e3e8"}, +] +"typing-extensions 4.5.0" = [ + {url = "https://files.pythonhosted.org/packages/31/25/5abcd82372d3d4a3932e1fa8c3dbf9efac10cc7c0d16e78467460571b404/typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, + {url = "https://files.pythonhosted.org/packages/d3/20/06270dac7316220643c32ae61694e451c98f8caf4c8eab3aa80a2bedf0df/typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, +] diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 9421a09..0000000 --- a/poetry.lock +++ /dev/null @@ -1,596 +0,0 @@ -[[package]] -name = "atomicwrites" -version = "1.4.1" -description = "Atomic file writes." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "attrs" -version = "22.1.0" -description = "Classes Without Boilerplate" -category = "main" -optional = false -python-versions = ">=3.5" - -[package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope-interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] -docs = ["furo", "sphinx", "zope-interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope-interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"] - -[[package]] -name = "black" -version = "22.6.0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "click" -version = "8.1.3" -description = "Composable command line interface toolkit" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.5" -description = "Cross-platform colored terminal text." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "commonmark" -version = "0.9.1" -description = "Python parser for the CommonMark Markdown spec" -category = "main" -optional = false -python-versions = "*" - -[package.extras] -test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] - -[[package]] -name = "coverage" -version = "6.4.4" -description = "Code coverage measurement for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "emoji" -version = "2.0.0" -description = "Emoji for Python" -category = "main" -optional = false -python-versions = "*" - -[package.extras] -dev = ["pytest", "coverage", "coveralls"] - -[[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "natsort" -version = "8.1.0" -description = "Simple yet flexible natural sorting in Python." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -fast = ["fastnumbers (>=2.0.0)"] -icu = ["PyICU (>=1.0.0)"] - -[[package]] -name = "packaging" -version = "21.3" -description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - -[[package]] -name = "pathspec" -version = "0.9.0" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[[package]] -name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] -test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] - -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "pydantic" -version = "1.9.2" -description = "Data validation and settings management using python type hints" -category = "main" -optional = false -python-versions = ">=3.6.1" - -[package.dependencies] -typing-extensions = ">=3.7.4.3" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] - -[[package]] -name = "pygments" -version = "2.13.0" -description = "Pygments is a syntax highlighting package written in Python." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -plugins = ["importlib-metadata"] - -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" -optional = false -python-versions = ">=3.6.8" - -[package.extras] -diagrams = ["railroad-diagrams", "jinja2"] - -[[package]] -name = "pytest" -version = "7.1.2" -description = "pytest: simple powerful testing with Python" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] - -[[package]] -name = "pytest-cov" -version = "3.0.0" -description = "Pytest plugin for measuring coverage." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] - -[[package]] -name = "pytest-mock" -version = "3.8.2" -description = "Thin-wrapper around the mock package for easier use with pytest" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -pytest = ">=5.0" - -[package.extras] -dev = ["pre-commit", "tox", "pytest-asyncio"] - -[[package]] -name = "pyyaml" -version = "6.0" -description = "YAML parser and emitter for Python" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "returns" -version = "0.19.0" -description = "Make your functions return something meaningful, typed, and safe!" -category = "main" -optional = false -python-versions = ">=3.7,<4.0" - -[package.dependencies] -typing-extensions = ">=4.0,<5.0" - -[[package]] -name = "rich" -version = "12.5.1" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -category = "main" -optional = false -python-versions = ">=3.6.3,<4.0.0" - -[package.dependencies] -commonmark = ">=0.9.0,<0.10.0" -pygments = ">=2.6.0,<3.0.0" - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] - -[[package]] -name = "seedir" -version = "0.3.1" -description = "Package for creating, editing, and reading folder tree diagrams." -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -emoji = "*" -natsort = "*" - -[[package]] -name = "sh" -version = "1.14.3" -description = "Python subprocess replacement" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "typer" -version = "0.6.1" -description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -click = ">=7.1.1,<9.0.0" - -[package.extras] -test = ["rich (>=10.11.0,<13.0.0)", "isort (>=5.0.6,<6.0.0)", "black (>=22.3.0,<23.0.0)", "mypy (==0.910)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<2.0.0)", "coverage (>=5.2,<6.0)", "pytest-cov (>=2.10.0,<3.0.0)", "pytest (>=4.4.0,<5.4.0)", "shellingham (>=1.3.0,<2.0.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mkdocs (>=1.1.2,<2.0.0)"] -dev = ["pre-commit (>=2.17.0,<3.0.0)", "flake8 (>=3.8.3,<4.0.0)", "autoflake (>=1.3.1,<2.0.0)"] -all = ["rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)", "colorama (>=0.4.3,<0.5.0)"] - -[[package]] -name = "typing-extensions" -version = "4.3.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" -optional = false -python-versions = ">=3.7" - -[metadata] -lock-version = "1.1" -python-versions = "^3.10" -content-hash = "e582e85120d3be9711b98d1064ca409be111a0ff02547fb5e382ff7e49814f06" - -[metadata.files] -atomicwrites = [] -attrs = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, -] -black = [ - {file = "black-22.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f586c26118bc6e714ec58c09df0157fe2d9ee195c764f630eb0d8e7ccce72e69"}, - {file = "black-22.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b270a168d69edb8b7ed32c193ef10fd27844e5c60852039599f9184460ce0807"}, - {file = "black-22.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6797f58943fceb1c461fb572edbe828d811e719c24e03375fd25170ada53825e"}, - {file = "black-22.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c85928b9d5f83b23cee7d0efcb310172412fbf7cb9d9ce963bd67fd141781def"}, - {file = "black-22.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6fe02afde060bbeef044af7996f335fbe90b039ccf3f5eb8f16df8b20f77666"}, - {file = "black-22.6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cfaf3895a9634e882bf9d2363fed5af8888802d670f58b279b0bece00e9a872d"}, - {file = "black-22.6.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94783f636bca89f11eb5d50437e8e17fbc6a929a628d82304c80fa9cd945f256"}, - {file = "black-22.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2ea29072e954a4d55a2ff58971b83365eba5d3d357352a07a7a4df0d95f51c78"}, - {file = "black-22.6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e439798f819d49ba1c0bd9664427a05aab79bfba777a6db94fd4e56fae0cb849"}, - {file = "black-22.6.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:187d96c5e713f441a5829e77120c269b6514418f4513a390b0499b0987f2ff1c"}, - {file = "black-22.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:074458dc2f6e0d3dab7928d4417bb6957bb834434516f21514138437accdbe90"}, - {file = "black-22.6.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a218d7e5856f91d20f04e931b6f16d15356db1c846ee55f01bac297a705ca24f"}, - {file = "black-22.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:568ac3c465b1c8b34b61cd7a4e349e93f91abf0f9371eda1cf87194663ab684e"}, - {file = "black-22.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6c1734ab264b8f7929cef8ae5f900b85d579e6cbfde09d7387da8f04771b51c6"}, - {file = "black-22.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9a3ac16efe9ec7d7381ddebcc022119794872abce99475345c5a61aa18c45ad"}, - {file = "black-22.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:b9fd45787ba8aa3f5e0a0a98920c1012c884622c6c920dbe98dbd05bc7c70fbf"}, - {file = "black-22.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7ba9be198ecca5031cd78745780d65a3f75a34b2ff9be5837045dce55db83d1c"}, - {file = "black-22.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3db5b6409b96d9bd543323b23ef32a1a2b06416d525d27e0f67e74f1446c8f2"}, - {file = "black-22.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:560558527e52ce8afba936fcce93a7411ab40c7d5fe8c2463e279e843c0328ee"}, - {file = "black-22.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b154e6bbde1e79ea3260c4b40c0b7b3109ffcdf7bc4ebf8859169a6af72cd70b"}, - {file = "black-22.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:4af5bc0e1f96be5ae9bd7aaec219c901a94d6caa2484c21983d043371c733fc4"}, - {file = "black-22.6.0-py3-none-any.whl", hash = "sha256:ac609cf8ef5e7115ddd07d85d988d074ed00e10fbc3445aee393e70164a2219c"}, - {file = "black-22.6.0.tar.gz", hash = "sha256:6c6d39e28aed379aec40da1c65434c77d75e65bb59a1e1c283de545fb4e7c6c9"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -commonmark = [] -coverage = [ - {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, - {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, - {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, - {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, - {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, - {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, - {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, - {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, - {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, - {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, - {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, - {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, - {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, - {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, - {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, - {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, -] -emoji = [ - {file = "emoji-2.0.0.tar.gz", hash = "sha256:297fac7ec9e86f7b602792c28eb6f04819ba67ab88a34c56afcde52243a9a105"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -natsort = [ - {file = "natsort-8.1.0-py3-none-any.whl", hash = "sha256:f59988d2f24e77b6b56f8a8f882d5df6b3b637e09e075abc67b486d59fba1a4b"}, - {file = "natsort-8.1.0.tar.gz", hash = "sha256:c7c1f3f27c375719a4dfcab353909fe39f26c2032a062a8c80cc844eaaca0445"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, -] -platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -pydantic = [ - {file = "pydantic-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c9e04a6cdb7a363d7cb3ccf0efea51e0abb48e180c0d31dca8d247967d85c6e"}, - {file = "pydantic-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fafe841be1103f340a24977f61dee76172e4ae5f647ab9e7fd1e1fca51524f08"}, - {file = "pydantic-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afacf6d2a41ed91fc631bade88b1d319c51ab5418870802cedb590b709c5ae3c"}, - {file = "pydantic-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ee0d69b2a5b341fc7927e92cae7ddcfd95e624dfc4870b32a85568bd65e6131"}, - {file = "pydantic-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ff68fc85355532ea77559ede81f35fff79a6a5543477e168ab3a381887caea76"}, - {file = "pydantic-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c0f5e142ef8217019e3eef6ae1b6b55f09a7a15972958d44fbd228214cede567"}, - {file = "pydantic-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:615661bfc37e82ac677543704437ff737418e4ea04bef9cf11c6d27346606044"}, - {file = "pydantic-1.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:328558c9f2eed77bd8fffad3cef39dbbe3edc7044517f4625a769d45d4cf7555"}, - {file = "pydantic-1.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bd446bdb7755c3a94e56d7bdfd3ee92396070efa8ef3a34fab9579fe6aa1d84"}, - {file = "pydantic-1.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0b214e57623a535936005797567231a12d0da0c29711eb3514bc2b3cd008d0f"}, - {file = "pydantic-1.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d8ce3fb0841763a89322ea0432f1f59a2d3feae07a63ea2c958b2315e1ae8adb"}, - {file = "pydantic-1.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b34ba24f3e2d0b39b43f0ca62008f7ba962cff51efa56e64ee25c4af6eed987b"}, - {file = "pydantic-1.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:84d76ecc908d917f4684b354a39fd885d69dd0491be175f3465fe4b59811c001"}, - {file = "pydantic-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4de71c718c9756d679420c69f216776c2e977459f77e8f679a4a961dc7304a56"}, - {file = "pydantic-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5803ad846cdd1ed0d97eb00292b870c29c1f03732a010e66908ff48a762f20e4"}, - {file = "pydantic-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8c5360a0297a713b4123608a7909e6869e1b56d0e96eb0d792c27585d40757f"}, - {file = "pydantic-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cdb4272678db803ddf94caa4f94f8672e9a46bae4a44f167095e4d06fec12979"}, - {file = "pydantic-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19b5686387ea0d1ea52ecc4cffb71abb21702c5e5b2ac626fd4dbaa0834aa49d"}, - {file = "pydantic-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:32e0b4fb13ad4db4058a7c3c80e2569adbd810c25e6ca3bbd8b2a9cc2cc871d7"}, - {file = "pydantic-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91089b2e281713f3893cd01d8e576771cd5bfdfbff5d0ed95969f47ef6d676c3"}, - {file = "pydantic-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e631c70c9280e3129f071635b81207cad85e6c08e253539467e4ead0e5b219aa"}, - {file = "pydantic-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b3946f87e5cef3ba2e7bd3a4eb5a20385fe36521d6cc1ebf3c08a6697c6cfb3"}, - {file = "pydantic-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5565a49effe38d51882cb7bac18bda013cdb34d80ac336428e8908f0b72499b0"}, - {file = "pydantic-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd67cb2c2d9602ad159389c29e4ca964b86fa2f35c2faef54c3eb28b4efd36c8"}, - {file = "pydantic-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4aafd4e55e8ad5bd1b19572ea2df546ccace7945853832bb99422a79c70ce9b8"}, - {file = "pydantic-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:d70916235d478404a3fa8c997b003b5f33aeac4686ac1baa767234a0f8ac2326"}, - {file = "pydantic-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ca86b525264daa5f6b192f216a0d1e860b7383e3da1c65a1908f9c02f42801"}, - {file = "pydantic-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1061c6ee6204f4f5a27133126854948e3b3d51fcc16ead2e5d04378c199b2f44"}, - {file = "pydantic-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e78578f0c7481c850d1c969aca9a65405887003484d24f6110458fb02cca7747"}, - {file = "pydantic-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5da164119602212a3fe7e3bc08911a89db4710ae51444b4224c2382fd09ad453"}, - {file = "pydantic-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ead3cd020d526f75b4188e0a8d71c0dbbe1b4b6b5dc0ea775a93aca16256aeb"}, - {file = "pydantic-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7d0f183b305629765910eaad707800d2f47c6ac5bcfb8c6397abdc30b69eeb15"}, - {file = "pydantic-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1a68f4f65a9ee64b6ccccb5bf7e17db07caebd2730109cb8a95863cfa9c4e55"}, - {file = "pydantic-1.9.2-py3-none-any.whl", hash = "sha256:78a4d6bdfd116a559aeec9a4cfe77dda62acc6233f8b56a716edad2651023e5e"}, - {file = "pydantic-1.9.2.tar.gz", hash = "sha256:8cb0bc509bfb71305d7a59d00163d5f9fc4530f0881ea32c74ff4f74c85f3d3d"}, -] -pygments = [ - {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, - {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, -] -pyparsing = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] -pytest = [ - {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, - {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, -] -pytest-cov = [ - {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, - {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, -] -pytest-mock = [] -pyyaml = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] -returns = [ - {file = "returns-0.19.0-py3-none-any.whl", hash = "sha256:ae3ce9e5165d1218905291b4d5881b4e8a86ca478437bef3b0af1de8df57ec69"}, - {file = "returns-0.19.0.tar.gz", hash = "sha256:4544bb67849c1ef1bbf7823759d433a773959e5b77a8fd06d01fef6d060f2ac5"}, -] -rich = [] -seedir = [ - {file = "seedir-0.3.1-py3-none-any.whl", hash = "sha256:9361daf7f2355621600e0a349e9c1e3539aecc7cb24b309b93880fa35d3d5007"}, - {file = "seedir-0.3.1.tar.gz", hash = "sha256:bbf6aef0fa51cd7e6ba8bdaff67a0913bc7199cd6302a92676fbae409112db54"}, -] -sh = [ - {file = "sh-1.14.3.tar.gz", hash = "sha256:e4045b6c732d9ce75d571c79f5ac2234edd9ae4f5fa9d59b09705082bdca18c7"}, -] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] -typer = [ - {file = "typer-0.6.1-py3-none-any.whl", hash = "sha256:54b19e5df18654070a82f8c2aa1da456a4ac16a2a83e6dcd9f170e291c56338e"}, - {file = "typer-0.6.1.tar.gz", hash = "sha256:2d5720a5e63f73eaf31edaa15f6ab87f35f0690f8ca233017d7d23d743a91d73"}, -] -typing-extensions = [ - {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, - {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, -] diff --git a/pyproject.toml b/pyproject.toml index 773efeb..360a535 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,39 +1,67 @@ -[tool.poetry] +[tool.pdm.build] +includes = [] +[build-system] +requires = ["pdm-backend"] +build-backend = "pdm.backend" + + +[project] +authors = [ + { name = "cătălin", email = "185504a9@duck.com" }, +] +requires-python = ">=3.10" +dependencies = [ + "typer<1.0.0,>=0.6.1", + "rich>=13.3.3", + "pydantic>=1.10.7", + "pyyaml>=6.0", + "pyrage>=1.0.3", + "pendulum>=2.1.2", +] name = "halig" version = "0.1.1" -description = "" -authors = ["cătălin <185504a9@duck.com>"] +description = "age-encrypted, file-based, note-taking CLI app" readme = "README.md" - -[tool.poetry.scripts] +[project.scripts] halig = "halig.main:app" -[tool.poetry.dependencies] -python = "^3.10" -typer = "^0.6.1" -rich = "^12.5.1" -sh = "^1.14.3" -pydantic = "^1.9.1" -PyYAML = "^6.0" -seedir = "^0.3.1" -pytest-mock = "^3.8.2" -returns = "^0.19.0" +[project.optional-dependencies] +testing = [ + "pytest>=7.2.2", + "pytest-cov>=4.0.0", + "pyfakefs>=5.1.0", + "pytest-clarity>=1.0.1", + "pytest-reportlog>=0.2.1", + "pytest-duration-insights>=0.1.1", + "pytest-pretty>=1.1.1", +] +linting = [ + "black>=23.3.0", + "ruff>=0.0.260", + "pyright>=1.1.301", + "mypy>=1.1.1", + "types-PyYAML>=6.0.12.9", + "pyrage-stubs>=1.0.1", +] +linters = [ + "pyrage-stubs>=1.0.1", +] +[tool.pyright] +reportMissingImports = false +reportMissingTypeStubs = false -[tool.poetry.group.linters.dependencies] -black = "^22.6.0" +[tool.ruff] +extend-select = ["W", "C90", "I", "N", "UP", "S", "BLE", "FBT", "B", "A", "COM", "C4", "DTZ", "T10", "EM", "ISC", "T20", "PT", "RSE", "RET", "SIM", "PTH", "ERA", "PGH", "PL", "TRY", "RUF"] +extend-ignore = ["S101", "ISC002"] - -[tool.poetry.group.test.dependencies] -pytest-mock = "^3.8.2" -pytest-cov = "^3.0.0" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" - -[tool.pytest.ini_options] -addopts = ['--maxfail=1', '-rf', "--cov=halig", '--junitxml=report.xml'] - -[tool.coverage.run] -omit = [".venv/**"] +[tool.mypy] +python_version = "3.11" +warn_return_any = true +warn_unused_configs = true +[[tool.mypy.overrides]] +module = [ + "pyrage", + "pyrage.ssh", +] +ignore_missing_imports = true diff --git a/sample.env b/sample.env new file mode 100644 index 0000000..f9acd78 --- /dev/null +++ b/sample.env @@ -0,0 +1,5 @@ +ROBOCES_REGISTRY_USERNAME= +ROBOCES_REGISTRY_PASSWORD= +PYPI_REGISTRY_USERNAME= +PYPI_REGISTRY_PASSWORD= + diff --git a/tests/commands/__init__.py b/tests/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..b187b10 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,98 @@ +import json +import os +from pathlib import Path + +import pytest +import yaml +from pyrage.ssh import Identity, Recipient + +from halig.encryption import Encryptor +from halig.settings import Settings + + +@pytest.fixture() +def halig_ssh_public_key(): + return "ssh-ed25519 " \ + "AAAAC3NzaC1lZDI1NTE5AAAAIGjHhIF/DlVCb2dRFMlKia7nij1Aq+zRDCaMIwe/VKDh" \ + " foo@bar" + + +@pytest.fixture() +def halig_ssh_private_key(): + return """-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBox4SBfw5VQm9nURTJSomu54o9QKvs0QwmjCMHv1Sg4QAAAJhvD2Jxbw9i +cQAAAAtzc2gtZWQyNTUxOQAAACBox4SBfw5VQm9nURTJSomu54o9QKvs0QwmjCMHv1Sg4Q +AAAEAZANW15ieou1ds73BlM1nqzyZ2A0454JnB3QirZycGv2jHhIF/DlVCb2dRFMlKia7n +ij1Aq+zRDCaMIwe/VKDhAAAAEXJvb3RANGNjNWUxOWYyYThiAQIDBA== +-----END OPENSSH PRIVATE KEY----- +""" + + +@pytest.fixture() +def ssh_identity(halig_ssh_private_key: str) -> Identity: + return Identity.from_buffer(halig_ssh_private_key.encode()) + + +@pytest.fixture() +def ssh_recipient(halig_ssh_public_key: str) -> Recipient: + return Recipient.from_str(halig_ssh_public_key) + + +@pytest.fixture() +def halig_path(fs, halig_ssh_public_key, halig_ssh_private_key) -> Path: + ssh_path = Path("~/.ssh").expanduser() + ssh_path.mkdir(parents=True) + + with (ssh_path / "id_ed25519").open("w") as f: + f.write(halig_ssh_private_key) + + with (ssh_path / "id_ed25519.pub").open("w") as f: + f.write(halig_ssh_public_key) + + halig_path = Path("~/.config/halig").expanduser() + halig_path.mkdir(parents=True) + return halig_path + + +@pytest.fixture() +def notebooks_path(halig_path) -> Path: + notebooks_path = Path("~/Notebooks").expanduser() + notebooks_path.mkdir(parents=True) + return notebooks_path + + +@pytest.fixture() +def settings(notebooks_path: Path) -> Settings: + return Settings(notebooks_root_path=notebooks_path) + + +@pytest.fixture() +def settings_file_path(halig_path: Path, notebooks_path: Path) -> Path: + yaml_file = halig_path / "halig.yml" + yaml_file.touch() + s = Settings(notebooks_root_path=notebooks_path) + # `.dict()` doesn't serialize some fields that yaml doesn't understand + serialized = json.loads(s.json()) + with yaml_file.open("w") as f: + yaml.safe_dump(serialized, f) + return yaml_file + + +@pytest.fixture() +def empty_file_path(halig_path: Path) -> Path: + empty_path = halig_path / "empty" + empty_path.touch() + return empty_path + + +@pytest.fixture() +def notebooks_root_path_envvar(notebooks_path: Path): + os.environ["HALIG_NOTEBOOKS_ROOT_PATH"] = str(notebooks_path) + yield notebooks_path + del os.environ["HALIG_NOTEBOOKS_ROOT_PATH"] + + +@pytest.fixture() +def encryptor(settings: Settings) -> Encryptor: + return Encryptor(settings) diff --git a/tests/file_fixtures.py b/tests/file_fixtures.py deleted file mode 100644 index e362937..0000000 --- a/tests/file_fixtures.py +++ /dev/null @@ -1,21 +0,0 @@ -import shutil -import tempfile -from pathlib import Path -from tempfile import NamedTemporaryFile - -import pytest - - -@pytest.fixture() -def tmpfile(): - _tmpfile = NamedTemporaryFile(delete=False) - with open(_tmpfile.name, "w") as file: - yield file - Path(_tmpfile.name).unlink() - - -@pytest.fixture() -def tmpdir(): - tmpdir = Path(tempfile.mkdtemp()) - yield tmpdir - shutil.rmtree(tmpdir) diff --git a/tests/test_config.py b/tests/test_config.py deleted file mode 100644 index bf81329..0000000 --- a/tests/test_config.py +++ /dev/null @@ -1,70 +0,0 @@ -from pathlib import Path -from tempfile import NamedTemporaryFile - -import pytest -import yaml -from pydantic import ValidationError - -from halig.config import get_config, Config, EncryptionKeysConfig -from halig.exceptions import ConfigFileDoesNotExist, ConfigFileIsInvalid -from tests.file_fixtures import tmpfile, tmpdir # noqa: 401 - - -def test_get_config_raises_config_file_does_not_exist(): - with pytest.raises(ConfigFileDoesNotExist): - get_config(Path("/foobar")) - - -def test_get_config_with_empty_file_raises_invalid_config_file(): - with pytest.raises(ConfigFileIsInvalid): - with NamedTemporaryFile() as f: - get_config(Path(f.name)) - - -def test_get_config_raises_invalid_config_file_00(tmpfile): # noqa: F811 - tmpfile.write("foobar") - with pytest.raises(ConfigFileIsInvalid): - get_config(Path(tmpfile.name)) - - -def test_get_config_raises_validation_error(tmpfile): # noqa: F811 - yaml.dump({"foo": "bar"}, tmpfile, Dumper=yaml.SafeDumper) - with pytest.raises(ValidationError): - get_config(Path(tmpfile.name)) - - -def test_get_config(tmpdir): # noqa: F811 - notes_root_path = Path(tmpdir / "notes") - notes_root_path.mkdir(exist_ok=True) - age_binary_path = Path(tmpdir / "age") - age_binary_path.touch(exist_ok=True) - encryption_keys_root_path = Path(tmpdir / "encryption_keys") - encryption_keys_root_path.mkdir(exist_ok=True) - public_key_path = Path(encryption_keys_root_path / "public.key") - public_key_path.touch(exist_ok=True) - private_key_path = Path(encryption_keys_root_path / "private.key") - private_key_path.touch(exist_ok=True) - config = Config( - notes_root_path=notes_root_path, - age_binary_path=age_binary_path, - encryption_keys=EncryptionKeysConfig( - public_key_path=public_key_path, private_key_path=private_key_path - ), - ) - raw_config = config.dict() - assert ( - config.notes_root_path == notes_root_path == Path(raw_config["notes_root_path"]) - ) - assert ( - config.age_binary_path == age_binary_path == Path(raw_config["age_binary_path"]) - ) - assert ( - config.encryption_keys.public_key_path - == public_key_path - == Path(raw_config["encryption_keys"]["public_key_path"]) - ) - assert ( - config.encryption_keys.private_key_path - == private_key_path - == Path(raw_config["encryption_keys"]["private_key_path"]) - ) diff --git a/tests/test_edit.py b/tests/test_edit.py deleted file mode 100644 index bb3de32..0000000 --- a/tests/test_edit.py +++ /dev/null @@ -1,79 +0,0 @@ -from pathlib import Path -from subprocess import CalledProcessError - -import pytest - -from halig.config import Config, EncryptionKeysConfig -from halig.edit_note import edit_note -from halig.exceptions import CouldNotEditTempfile -from tests.file_fixtures import tmpfile, tempfile # noqa: F401 - -from sh import age, ssh_keygen, yes - - -@pytest.fixture() -def notes_path(tmpdir): # noqa: F811 - notes_path = Path(tmpdir.dirname) / "notes" - notes_path.mkdir(exist_ok=True) - - yield notes_path - - -@pytest.fixture() -def config(notes_path): # noqa: F811 - keys_path = Path(notes_path.parent / ".ssh") - keys_path.mkdir(exist_ok=True) - private_key_path = keys_path / "key" - public_key_path = keys_path / "key.pub" - - ssh_keygen(yes(_piped=True), t="ed25519", f=str(private_key_path)) - - config = Config( - notes_root_path=notes_path, - encryption_keys=EncryptionKeysConfig( - public_key_path=public_key_path, - private_key_path=private_key_path, - ), - ) - - note_path = notes_path / "note" - note_path.touch(exist_ok=True) - with open(note_path, "w") as f: - f.write("this is a test") - - age( - "-R", - str(config.encryption_keys.public_key_path), - str(note_path), - _out=f"{note_path}.age", - ) - - yield config - - -def mock_subprocess(args: list): - with open(args[1], "w") as f: - f.write("mocked") - - -def test_edit_note(config: Config, mocker): # noqa: F811 - mocker.patch("subprocess.call", side_effect=mock_subprocess) - edit_note(config.notes_root_path / "note.age", config) - assert ( - age( - "-d", - "-i", - config.encryption_keys.private_key_path, - config.notes_root_path / "note.age", - ) - == "mocked" - ) - - -def test_edit_not_raises_could_not_edit_tempfile(config: Config, mocker): # noqa: F811 - mocker.patch( - "subprocess.call", - side_effect=CalledProcessError(returncode=1, cmd="foo", output="mocked error"), - ) - with pytest.raises(CouldNotEditTempfile): - edit_note(config.notes_root_path / "note.age", config) diff --git a/tests/test_encryption.py b/tests/test_encryption.py new file mode 100644 index 0000000..f6e9179 --- /dev/null +++ b/tests/test_encryption.py @@ -0,0 +1,54 @@ +from pyrage import decrypt, encrypt, x25519 + +from halig.encryption import Encryptor +from halig.settings import Settings + + +def test_instance_encryptor_from_age_keys(halig_path, notebooks_path): + identity = x25519.Identity.generate() + identity_path = halig_path / "identity.key" + identity_path.touch() + recipient_path = halig_path / "recipient.key" + recipient_path.touch() + with identity_path.open("w") as f: + f.write(str(identity)) + + with recipient_path.open("w") as f: + f.write(str(identity.to_public())) + + settings = Settings( + notebooks_root_path=notebooks_path, + identity_path=identity_path, + recipient_path=recipient_path, + ) + assert Encryptor(settings) + + +def test_encrypt(encryptor: Encryptor, ssh_identity): + unencrypted_data = "foo" + encrypted_data = encryptor.encrypt(unencrypted_data) + + assert isinstance(encrypted_data, bytes) + assert unencrypted_data == decrypt(encrypted_data, [ssh_identity]).decode() + + +def test_encrypt_bytes(encryptor: Encryptor, ssh_identity): + unencrypted_data = b"foo" + encrypted_data = encryptor.encrypt(unencrypted_data) + + assert isinstance(encrypted_data, bytes) + assert unencrypted_data == decrypt(encrypted_data, [ssh_identity]) + + +def test_decrypt(encryptor: Encryptor, ssh_recipient): + unencrypted_data = "foo" + encrypted_data = encrypt(unencrypted_data.encode(), [ssh_recipient]) + decrypted_data = encryptor.decrypt(encrypted_data) + assert decrypted_data.decode() == unencrypted_data + + +def test_decrypt_bytes(encryptor: Encryptor, ssh_recipient): + unencrypted_data = b"foo" + encrypted_data = encrypt(unencrypted_data, [ssh_recipient]) + decrypted_data = encryptor.decrypt(encrypted_data) + assert decrypted_data == unencrypted_data diff --git a/tests/test_new_note.py b/tests/test_new_note.py deleted file mode 100644 index a57ba72..0000000 --- a/tests/test_new_note.py +++ /dev/null @@ -1,95 +0,0 @@ -from pathlib import Path -from subprocess import CalledProcessError - -import pytest - -from halig.config import Config, EncryptionKeysConfig -from halig.edit_note import edit_note -from halig.exceptions import CouldNotEditTempfile -from halig.new_note import new_note -from tests.file_fixtures import tmpfile, tempfile # noqa: F401 - -from sh import age, ssh_keygen, yes - - -@pytest.fixture() -def notes_path(tmpdir): # noqa: F811 - notes_path = Path(tmpdir.dirname) / "notes" - notes_path.mkdir(exist_ok=True) - - yield notes_path - - -@pytest.fixture() -def config(notes_path): # noqa: F811 - keys_path = Path(notes_path.parent / ".ssh") - keys_path.mkdir(exist_ok=True) - private_key_path = keys_path / "key" - public_key_path = keys_path / "key.pub" - - ssh_keygen(yes(_piped=True), t="ed25519", f=str(private_key_path)) - - config = Config( - notes_root_path=notes_path, - encryption_keys=EncryptionKeysConfig( - public_key_path=public_key_path, - private_key_path=private_key_path, - ), - ) - - note_path = notes_path / "note" - note_path.touch(exist_ok=True) - with open(note_path, "w") as f: - f.write("this is a test") - - age( - "-R", - str(config.encryption_keys.public_key_path), - str(note_path), - _out=f"{note_path}.age", - ) - - yield config - - -def mock_subprocess(args: list): - with open(args[1], "a") as f: - f.write(" mocked") - - -def test_new_note_default_template_data(config: Config, mocker): # noqa: F811 - mocker.patch("subprocess.call", side_effect=mock_subprocess) - new_note(config.notes_root_path / "new_default_note.age", config) - note_contents = age( - "-d", - "-i", - config.encryption_keys.private_key_path, - config.notes_root_path / "new_default_note.age", - ) - assert note_contents == f"{config._default_template_data} mocked" - - -def test_new_note_custom_template_data(config: Config, mocker): # noqa: F811 - mocker.patch("subprocess.call", side_effect=mock_subprocess) - template_path = config.notes_root_path / "template.halig" - template_path.touch(exist_ok=True) - with open(template_path, "w") as f: - f.write("template string") - new_note(config.notes_root_path / "new_note.age", config) - template_path.unlink() - note_contents = age( - "-d", - "-i", - config.encryption_keys.private_key_path, - config.notes_root_path / "new_note.age", - ) - assert note_contents == "template string mocked" - - -def test_new_not_raises_could_not_edit_tempfile(config: Config, mocker): # noqa: F811 - mocker.patch( - "subprocess.call", - side_effect=CalledProcessError(returncode=1, cmd="foo", output="mocked error"), - ) - with pytest.raises(CouldNotEditTempfile): - edit_note(config.notes_root_path / "note.age", config) diff --git a/tests/test_settings.py b/tests/test_settings.py new file mode 100644 index 0000000..46eaa44 --- /dev/null +++ b/tests/test_settings.py @@ -0,0 +1,42 @@ +from pathlib import Path + +import pytest + +from halig.settings import Settings, load_from_file + + +def test_settings_from_env(settings: Settings, notebooks_root_path_envvar): + from_env_settings = Settings() # type: ignore[call-arg] + assert from_env_settings.notebooks_root_path == settings.notebooks_root_path + + +def test_settings_from_non_existing_file_raises_value_error(): + with pytest.raises(ValueError, match="field required"): + Settings() # type: ignore[call-arg] + + +def test_load_from_file(notebooks_path: Path, settings_file_path: Path): + settings = load_from_file(settings_file_path) + assert settings.notebooks_root_path == notebooks_path + + +def test_load_from_non_xdg_home_config_raises_file_not_found_error(fs): + path = Path("~/.config").expanduser() + with pytest.raises(FileNotFoundError, match=f"File {path} does not exist"): + load_from_file() + + +def test_load_from_existing_standard_file(settings_file_path: Path, settings: Settings): + standard_settings = load_from_file() + assert standard_settings.notebooks_root_path == settings.notebooks_root_path + + +def test_load_from_empty_file_raises_value_error(empty_file_path: Path): + with pytest.raises(ValueError, match=f"File {empty_file_path} is empty"): + load_from_file(empty_file_path) + + +def test_load_from_non_existing_file_path_raises_file_not_found_error(halig_path: Path): + file = halig_path / "some_invalid_file.yml" + with pytest.raises(FileNotFoundError, match=f"File {file} does not exist"): + load_from_file(file) diff --git a/tests/test_utils.py b/tests/test_utils.py deleted file mode 100644 index 7707232..0000000 --- a/tests/test_utils.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -from pathlib import Path - -from halig.utils import resolve_path - - -def test_resolve_absolute_path(): - path = Path("/foo/bar/baz") - assert resolve_path(path) == path - - -def test_resolve_user_path(): - path = Path("~/foo/bar/baz") - assert resolve_path(path) == path.expanduser() - - -def test_resolve_path_with_envvars(): - os.environ["FOO"] = "foo" - os.environ["BAR"] = "bar" - path = Path("/${FOO}/${BAR}") - assert resolve_path(path) == Path("/foo/bar") - - -def test_resolve_relative_path(): - path = Path("foo/bar/baz") - assert resolve_path(path) == path.resolve() - - -def test_resolve_path_all(): - os.environ["FOO"] = "foo" - os.environ["BAR"] = "bar" - path = Path("foo/bar/$FOO/../$BAR") - assert resolve_path(path) == Path(os.path.expandvars(path)).resolve().expanduser()