feat: move project from poetry to pdm, rewrite from scratch and add

basic `notebooks`, `edit` and `show` commands
This commit is contained in:
cătălin 2023-04-01 12:37:10 +02:00
commit d3ad87211e
Signed by: catalin
GPG key ID: 686088EF78EE4083
35 changed files with 1309 additions and 1434 deletions

View file

@ -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

3
.gitignore vendored
View file

@ -212,3 +212,6 @@ dmypy.json
# Cython debug symbols # Cython debug symbols
cython_debug/ cython_debug/
report.xml report.xml
.pdm-python
reportlog.json
.ruff_cache/

View file

@ -1,9 +1,11 @@
default_language_version: default_language_version:
python: python3.10 python: python3.10
files: ^halig|tests$
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0 rev: v4.4.0
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
args: [ --markdown-linebreak-ext=md ] args: [ --markdown-linebreak-ext=md ]
@ -18,52 +20,34 @@ repos:
- id: debug-statements - id: debug-statements
- id: mixed-line-ending - id: mixed-line-ending
args: [ --fix=lf ] args: [ --fix=lf ]
- id: detect-private-key
- repo: https://github.com/pre-commit/pygrep-hooks - repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v1.9.0 rev: v0.0.260
hooks: hooks:
- id: python-check-blanket-noqa - id: ruff
- id: python-use-type-annotations args:
- --fix
- --exit-non-zero-on-fix
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 22.6.0 rev: 23.3.0
hooks: hooks:
- id: black - id: black
pass_filenames: false pass_filenames: false
args: args:
- "halig" - "halig"
- repo: https://gitlab.com/pycqa/flake8 - repo: local
rev: 3.9.2
hooks: 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 - id: mypy
files: ^halig/ name: mypy
additional_dependencies: entry: pdm run mypy
- types-deprecated==1.2.8 language: system
- types-pyyaml==6.0.11 types: [ python ]
- repo: https://github.com/asottile/pyupgrade - id: pyright
rev: v2.34.0 name: pyright
hooks: entry: pdm run pyright
- id: pyupgrade language: system
types: [ python ]
- repo: https://github.com/PyCQA/bandit
rev: 1.7.4
hooks:
- id: bandit
files: ^darkroot/
args: [ -r ]

16
Makefile Normal file
View file

@ -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

View file

@ -1,10 +1,23 @@
# halig # 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 ```shell
$ halig init # create and write $HOME/.config/halig/halig.yml
$ halig edit some_notebook # edit today's note $ halig edit some_notebook # edit today's note
$ halig edit some_notebook/foo # edit /path/to/some_notebook/foo.age $ halig edit some_notebook/foo # edit /path/to/some_notebook/foo.age
$ halig notebooks # list current notebooks $ halig notebooks # list current notebooks
``` ```
## tui mode
wip

View file

@ -0,0 +1,3 @@
from typer import Typer
app = Typer()

0
halig/app.py Normal file
View file

View file

23
halig/commands/base.py Normal file
View file

@ -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

75
halig/commands/edit.py Normal file
View file

@ -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)

View file

@ -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))

34
halig/commands/show.py Normal file
View file

@ -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)

View file

@ -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

View file

@ -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()

34
halig/encryption.py Normal file
View file

@ -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]

View file

@ -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

View file

@ -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)

90
halig/main.py Executable file → Normal file
View file

@ -1,81 +1,35 @@
#!/usr/bin/env python3 #!/usr/bin/env python
from datetime import datetime
from pathlib import Path from pathlib import Path
import yaml from halig import app
from typer import Typer from halig.commands.edit import EditCommand
from halig.commands.notebooks import NotebooksCommand
from halig import logger from halig.commands.show import ShowCommand
from halig.config import ( from halig.settings import load_from_file
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)
@app.command() @app.command()
def init(force_recreate: bool = False): def notebooks(max_depth: int = -1):
"""Create the config file. If the config file already exists, it'll not if max_depth < 0:
be overwritten unless the `--force-recreate` flag is provided max_depth = float("inf") # type: ignore[assignment]
""" settings = load_from_file()
if DEFAULT_CONFIGURATION_PATH.exists() and not force_recreate: command = NotebooksCommand(settings=settings, max_depth=max_depth)
logger.error( command.run()
"""$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)
@app.command() @app.command()
@handle_errors def edit(note: Path):
def notebooks( settings = load_from_file()
print_files: bool = False, command = EditCommand(settings=settings, note_path=note)
print_hidden: bool = False, command.run()
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
)
@app.command() @app.command()
@handle_errors def show(note: Path):
def edit(path: Path, configuration_path: Path = DEFAULT_CONFIGURATION_PATH): settings = load_from_file()
"""Edit a new or existing note by providing a relative path. The relative path command = ShowCommand(settings=settings, note_path=note)
will be appended to the notes root path that is specified in the configuration file. command.run()
Note that if only a dir is provided, an attempt to create or open
`<dir>/<current date>.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)
app() if __name__ == "__main__":
app()

View file

@ -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()

37
halig/settings.py Normal file
View file

@ -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)

View file

@ -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

16
noxfile.py Normal file
View file

@ -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)

722
pdm.lock generated Normal file
View file

@ -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"},
]

596
poetry.lock generated
View file

@ -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"},
]

View file

@ -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" name = "halig"
version = "0.1.1" version = "0.1.1"
description = "" description = "age-encrypted, file-based, note-taking CLI app"
authors = ["cătălin <185504a9@duck.com>"]
readme = "README.md" readme = "README.md"
[project.scripts]
[tool.poetry.scripts]
halig = "halig.main:app" halig = "halig.main:app"
[tool.poetry.dependencies] [project.optional-dependencies]
python = "^3.10" testing = [
typer = "^0.6.1" "pytest>=7.2.2",
rich = "^12.5.1" "pytest-cov>=4.0.0",
sh = "^1.14.3" "pyfakefs>=5.1.0",
pydantic = "^1.9.1" "pytest-clarity>=1.0.1",
PyYAML = "^6.0" "pytest-reportlog>=0.2.1",
seedir = "^0.3.1" "pytest-duration-insights>=0.1.1",
pytest-mock = "^3.8.2" "pytest-pretty>=1.1.1",
returns = "^0.19.0" ]
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] [tool.ruff]
black = "^22.6.0" 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.mypy]
[tool.poetry.group.test.dependencies] python_version = "3.11"
pytest-mock = "^3.8.2" warn_return_any = true
pytest-cov = "^3.0.0" warn_unused_configs = true
[[tool.mypy.overrides]]
[build-system] module = [
requires = ["poetry-core"] "pyrage",
build-backend = "poetry.core.masonry.api" "pyrage.ssh",
]
[tool.pytest.ini_options] ignore_missing_imports = true
addopts = ['--maxfail=1', '-rf', "--cov=halig", '--junitxml=report.xml']
[tool.coverage.run]
omit = [".venv/**"]

5
sample.env Normal file
View file

@ -0,0 +1,5 @@
ROBOCES_REGISTRY_USERNAME=
ROBOCES_REGISTRY_PASSWORD=
PYPI_REGISTRY_USERNAME=
PYPI_REGISTRY_PASSWORD=

View file

98
tests/conftest.py Normal file
View file

@ -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)

View file

@ -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)

View file

@ -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"])
)

View file

@ -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)

54
tests/test_encryption.py Normal file
View file

@ -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

View file

@ -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)

42
tests/test_settings.py Normal file
View file

@ -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)

View file

@ -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()