diff --git a/CLI.md b/CLI.md index 65ad938..541911a 100644 --- a/CLI.md +++ b/CLI.md @@ -16,6 +16,7 @@ $ podping [OPTIONS] COMMAND [ARGS]... * `--livetest / --no-livetest`: Use live Hive chain but write with id=podping-livetest. Enable this if you want to validate posting to Hive without notifying podping watchers. Used internally for end-to-end tests. [env var: PODPING_LIVETEST; default: False] * `--dry-run / --no-dry-run`: Run through all posting logic without posting to the chain. [env var: PODPING_DRY_RUN; default: False] * `--status / --no-status`: Periodically prints a status message. Runs every diagnostic_report_period defined in podping_settings [env var: PODPING_STATUS; default: True] +* `--hive-operation-period INTEGER`: By default the Hivewriter will wait a few seconds gathering IRIs before sending the next batch. This balances resource usage against speed. If this is set here, the setting will override any settings sent by a config update. [env var: PODPING_HIVE_OPERATION_PERIOD; default: 3] * `--ignore-config-updates / --no-ignore-config-updates`: By default, podping will periodically pull new settings from the configured Hive control account, allowing real time updates to adapt to changes in the Hive network. This lets you ignore these updates if needed. [env var: PODPING_IGNORE_CONFIG_UPDATES; default: False] * `--i-know-what-im-doing`: Set this if you really want to listen on all interfaces. [env var: PODPING_I_KNOW_WHAT_IM_DOING; default: False] * `--debug / --no-debug`: Print debug log messages [env var: PODPING_DEBUG; default: False] diff --git a/Dockerfile b/Dockerfile index 73b5823..f51fb92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install --user poetry \ && poetry config virtualenvs.in-project true \ - && poetry install --no-root --no-dev --no-interaction --no-ansi + && poetry install --no-root --only main --no-interaction --no-ansi FROM docker.io/python:3.10-slim-bullseye AS app @@ -53,7 +53,7 @@ COPY --chown=podping:podping . . RUN pip install --upgrade pip \ && pip install poetry \ && poetry config virtualenvs.in-project true \ - && poetry install --no-dev --no-interaction --no-ansi + && poetry install --only main --no-interaction --no-ansi # podping command installs here ENV PATH="/home/podping/app/.venv/bin:${PATH}" diff --git a/poetry.lock b/poetry.lock index 1dd3ea9..ace11ce 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,8 +11,8 @@ idna = ">=2.8" sniffio = ">=1.1" [package.extras] -doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] -test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] trio = ["trio (>=0.16)"] [[package]] @@ -24,15 +24,7 @@ optional = false python-versions = ">=3.7" [package.extras] -tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] - -[[package]] -name = "atomicwrites" -version = "1.4.1" -description = "Atomic file writes." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] [[package]] name = "attrs" @@ -43,14 +35,14 @@ 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"] +dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] +docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] +tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "backoff" -version = "2.1.2" +version = "2.2.1" description = "Function decoration for backoff and retry" category = "main" optional = false @@ -71,9 +63,9 @@ PyYAML = ">=5.3.1" stevedore = ">=1.20.0" [package.extras] -test = ["coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml", "beautifulsoup4 (>=4.8.0)", "pylint (==1.9.4)"] +test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml"] toml = ["toml"] -yaml = ["pyyaml"] +yaml = ["PyYAML"] [[package]] name = "black" @@ -91,7 +83,7 @@ platformdirs = ">=2" tomli = ">=0.2.6,<2.0.0" typing-extensions = [ {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, - {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, + {version = ">=3.10.0.0,<3.10.0.1 || >3.10.0.1", markers = "python_version >= \"3.10\""}, ] [package.extras] @@ -101,6 +93,14 @@ jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] python2 = ["typed-ast (>=1.4.3)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "cachetools" +version = "5.2.0" +description = "Extensible memoizing collections and decorators" +category = "main" +optional = false +python-versions = "~=3.7" + [[package]] name = "capnpy" version = "0.9.0" @@ -117,7 +117,7 @@ six = "*" [[package]] name = "certifi" -version = "2022.6.15" +version = "2022.9.24" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false @@ -136,7 +136,7 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "2.1.0" +version = "2.1.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false @@ -163,7 +163,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.4.3" +version = "6.5.0" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -176,7 +176,7 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 toml = ["tomli"] [[package]] -name = "cython" +name = "Cython" version = "0.29.32" description = "The Cython compiler for writing C extensions for the Python language." category = "main" @@ -220,16 +220,16 @@ gmpy2 = ["gmpy2"] [[package]] name = "flake8" -version = "4.0.1" +version = "5.0.4" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.1" [package.dependencies] -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.8.0,<2.9.0" -pyflakes = ">=2.4.0,<2.5.0" +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.9.0,<2.10.0" +pyflakes = ">=2.5.0,<2.6.0" [[package]] name = "gitdb" @@ -243,8 +243,8 @@ python-versions = ">=3.6" smmap = ">=3.0.1,<6" [[package]] -name = "gitpython" -version = "3.1.27" +name = "GitPython" +version = "3.1.28" description = "GitPython is a python library used to interact with Git repositories" category = "dev" optional = false @@ -294,14 +294,14 @@ rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" [package.extras] -brotli = ["brotlicffi", "brotli"] -cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10,<13)", "pygments (>=2.0.0,<3.0.0)"] +brotli = ["brotli", "brotlicffi"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "idna" -version = "3.3" +version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -324,44 +324,45 @@ optional = false python-versions = ">=3.6.1,<4.0" [package.extras] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] +requirements_deprecated_finder = ["pip-api", "pipreqs"] [[package]] name = "lighthive" -version = "0.3.3" +version = "0.4.0" description = "A light python client to interact with the HIVE blockchain" category = "main" optional = false python-versions = "*" [package.dependencies] -backoff = "*" +backoff = ">=2.0,<3.0" +cachetools = "*" dateutils = "*" ecdsa = "*" httpx = "*" requests = "*" [package.extras] -dev = ["requests-mock"] +dev = ["requests_mock"] [[package]] name = "mccabe" -version = "0.6.1" +version = "0.7.0" description = "McCabe checker, plugin for flake8" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "mypy" -version = "0.950" +version = "0.982" description = "Optional static typing for Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] mypy-extensions = ">=0.4.3" @@ -405,15 +406,15 @@ dev = ["check-manifest"] [[package]] name = "pathspec" -version = "0.9.0" +version = "0.10.1" 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" +python-versions = ">=3.7" [[package]] name = "pbr" -version = "5.9.0" +version = "5.10.0" description = "Python Build Reasonableness" category = "dev" optional = false @@ -428,8 +429,8 @@ 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)"] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] [[package]] name = "pluggy" @@ -453,11 +454,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pycodestyle" -version = "2.8.0" +version = "2.9.1" description = "Python style guide checker" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" [[package]] name = "pycparser" @@ -469,14 +470,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pydantic" -version = "1.9.1" +version = "1.10.2" description = "Data validation and settings management using python type hints" category = "main" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" [package.dependencies] -typing-extensions = ">=3.7.4.3" +typing-extensions = ">=4.1.0" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] @@ -484,11 +485,11 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pyflakes" -version = "2.4.0" +version = "2.5.0" description = "passive checker of Python programs" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [[package]] name = "pyparsing" @@ -499,7 +500,7 @@ optional = false python-versions = ">=3.6.8" [package.extras] -diagrams = ["railroad-diagrams", "jinja2"] +diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pypytools" @@ -514,14 +515,13 @@ py = "*" [[package]] name = "pytest" -version = "7.1.2" +version = "7.1.3" description = "pytest: simple powerful testing with Python" category = "dev" 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 = "*" @@ -535,7 +535,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. [[package]] name = "pytest-asyncio" -version = "0.18.3" +version = "0.19.0" description = "Pytest support for asyncio" category = "dev" optional = false @@ -545,11 +545,11 @@ python-versions = ">=3.7" pytest = ">=6.1.0" [package.extras] -testing = ["coverage (==6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (==0.931)", "pytest-trio (>=0.7.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] [[package]] name = "pytest-cov" -version = "3.0.0" +version = "4.0.0" description = "Pytest plugin for measuring coverage." category = "dev" optional = false @@ -560,11 +560,11 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "pytest-mock" -version = "3.8.2" +version = "3.10.0" description = "Thin-wrapper around the mock package for easier use with pytest" category = "dev" optional = false @@ -574,7 +574,7 @@ python-versions = ">=3.7" pytest = ">=5.0" [package.extras] -dev = ["pre-commit", "tox", "pytest-asyncio"] +dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "pytest-timeout" @@ -600,14 +600,14 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2022.1" +version = "2022.4" description = "World timezone definitions, modern and historical" category = "main" optional = false python-versions = "*" [[package]] -name = "pyyaml" +name = "PyYAML" version = "6.0" description = "YAML parser and emitter for Python" category = "dev" @@ -616,7 +616,7 @@ python-versions = ">=3.6" [[package]] name = "pyzmq" -version = "22.3.0" +version = "24.0.1" description = "Python bindings for 0MQ" category = "main" optional = false @@ -700,11 +700,11 @@ python-versions = ">=3.6" [[package]] name = "sniffio" -version = "1.2.0" +version = "1.3.0" description = "Sniff out which async library your code is running under" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [[package]] name = "stevedore" @@ -739,10 +739,10 @@ colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"a shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} [package.extras] -test = ["pytest-xdist (>=1.32.0,<2.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "mypy (==0.782)", "black (>=19.10b0,<20.0b0)", "isort (>=5.0.6,<6.0.0)", "shellingham (>=1.3.0,<2.0.0)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "coverage (>=5.2,<6.0)"] all = ["colorama (>=0.4.3,<0.5.0)", "shellingham (>=1.3.0,<2.0.0)"] dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)"] -doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=5.4.0,<6.0.0)", "markdown-include (>=0.5.1,<0.6.0)"] +doc = ["markdown-include (>=0.5.1,<0.6.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=5.4.0,<6.0.0)"] +test = ["black (>=19.10b0,<20.0b0)", "coverage (>=5.2,<6.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.782)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<2.0.0)", "shellingham (>=1.3.0,<2.0.0)"] [[package]] name = "typer-cli" @@ -759,7 +759,7 @@ typer = ">=0.3.0,<0.4.0" [[package]] name = "typing-extensions" -version = "4.3.0" +version = "4.4.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false @@ -767,15 +767,15 @@ python-versions = ">=3.7" [[package]] name = "urllib3" -version = "1.26.11" +version = "1.26.12" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" [package.extras] -brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [extras] @@ -784,7 +784,7 @@ server = ["pyzmq"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "fd2f37d4193c47c118356e52a310dd58f9e637edc5b02c5d7a111cfcc8cc21c5" +content-hash = "7ea13c8285a8f95efbbfef8a8475bd73c97d68fbe053ff3326df9283534e8295" [metadata.files] anyio = [ @@ -795,11 +795,13 @@ asgiref = [ {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"}, ] -atomicwrites = [] -attrs = [] +attrs = [ + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, +] backoff = [ - {file = "backoff-2.1.2-py3-none-any.whl", hash = "sha256:b135e6d7c7513ba2bfd6895bc32bc8c66c6f3b0279b4c6cd866053cfd7d3126b"}, - {file = "backoff-2.1.2.tar.gz", hash = "sha256:407f1bc0f22723648a8880821b935ce5df8475cf04f7b6b5017ae264d30f6069"}, + {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, + {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, ] bandit = [ {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"}, @@ -809,6 +811,10 @@ black = [ {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, ] +cachetools = [ + {file = "cachetools-5.2.0-py3-none-any.whl", hash = "sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db"}, + {file = "cachetools-5.2.0.tar.gz", hash = "sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757"}, +] capnpy = [ {file = "capnpy-0.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cecae85a51930a46a0caa2a986bf28965ae54a1123b304ec7793ce0241fe7e21"}, {file = "capnpy-0.9.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ed997a9df9509abdd259123d51d72b38b61ebb55688c364907eb93d4bc66aaa6"}, @@ -818,11 +824,79 @@ capnpy = [ {file = "capnpy-0.9.0.tar.gz", hash = "sha256:127b089a2df2c7b9da6f4b63574626a92c63a0fd01c26dc018de6de617297dc7"}, ] certifi = [ - {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, - {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"}, + {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, + {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, +] +cffi = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, ] -cffi = [] -charset-normalizer = [] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, @@ -831,8 +905,100 @@ colorama = [ {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, ] -coverage = [] -cython = [] +coverage = [ + {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, + {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, + {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, + {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, + {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, + {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, + {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, + {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, + {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, + {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, + {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, + {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, + {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, + {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, + {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, + {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, +] +Cython = [ + {file = "Cython-0.29.32-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:39afb4679b8c6bf7ccb15b24025568f4f9b4d7f9bf3cbd981021f542acecd75b"}, + {file = "Cython-0.29.32-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dbee03b8d42dca924e6aa057b836a064c769ddfd2a4c2919e65da2c8a362d528"}, + {file = "Cython-0.29.32-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ba622326f2862f9c1f99ca8d47ade49871241920a352c917e16861e25b0e5c3"}, + {file = "Cython-0.29.32-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e6ffa08aa1c111a1ebcbd1cf4afaaec120bc0bbdec3f2545f8bb7d3e8e77a1cd"}, + {file = "Cython-0.29.32-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:97335b2cd4acebf30d14e2855d882de83ad838491a09be2011745579ac975833"}, + {file = "Cython-0.29.32-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:06be83490c906b6429b4389e13487a26254ccaad2eef6f3d4ee21d8d3a4aaa2b"}, + {file = "Cython-0.29.32-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:eefd2b9a5f38ded8d859fe96cc28d7d06e098dc3f677e7adbafda4dcdd4a461c"}, + {file = "Cython-0.29.32-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5514f3b4122cb22317122a48e175a7194e18e1803ca555c4c959d7dfe68eaf98"}, + {file = "Cython-0.29.32-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:656dc5ff1d269de4d11ee8542f2ffd15ab466c447c1f10e5b8aba6f561967276"}, + {file = "Cython-0.29.32-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:cdf10af3e2e3279dc09fdc5f95deaa624850a53913f30350ceee824dc14fc1a6"}, + {file = "Cython-0.29.32-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:3875c2b2ea752816a4d7ae59d45bb546e7c4c79093c83e3ba7f4d9051dd02928"}, + {file = "Cython-0.29.32-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:79e3bab19cf1b021b613567c22eb18b76c0c547b9bc3903881a07bfd9e7e64cf"}, + {file = "Cython-0.29.32-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0595aee62809ba353cebc5c7978e0e443760c3e882e2c7672c73ffe46383673"}, + {file = "Cython-0.29.32-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0ea8267fc373a2c5064ad77d8ff7bf0ea8b88f7407098ff51829381f8ec1d5d9"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:c8e8025f496b5acb6ba95da2fb3e9dacffc97d9a92711aacfdd42f9c5927e094"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:afbce249133a830f121b917f8c9404a44f2950e0e4f5d1e68f043da4c2e9f457"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:513e9707407608ac0d306c8b09d55a28be23ea4152cbd356ceaec0f32ef08d65"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e83228e0994497900af954adcac27f64c9a57cd70a9ec768ab0cb2c01fd15cf1"}, + {file = "Cython-0.29.32-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ea1dcc07bfb37367b639415333cfbfe4a93c3be340edf1db10964bc27d42ed64"}, + {file = "Cython-0.29.32-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8669cadeb26d9a58a5e6b8ce34d2c8986cc3b5c0bfa77eda6ceb471596cb2ec3"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:ed087eeb88a8cf96c60fb76c5c3b5fb87188adee5e179f89ec9ad9a43c0c54b3"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3f85eb2343d20d91a4ea9cf14e5748092b376a64b7e07fc224e85b2753e9070b"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:63b79d9e1f7c4d1f498ab1322156a0d7dc1b6004bf981a8abda3f66800e140cd"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e1958e0227a4a6a2c06fd6e35b7469de50adf174102454db397cec6e1403cce3"}, + {file = "Cython-0.29.32-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:856d2fec682b3f31583719cb6925c6cdbb9aa30f03122bcc45c65c8b6f515754"}, + {file = "Cython-0.29.32-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:479690d2892ca56d34812fe6ab8f58e4b2e0129140f3d94518f15993c40553da"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:67fdd2f652f8d4840042e2d2d91e15636ba2bcdcd92e7e5ffbc68e6ef633a754"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:4a4b03ab483271f69221c3210f7cde0dcc456749ecf8243b95bc7a701e5677e0"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:40eff7aa26e91cf108fd740ffd4daf49f39b2fdffadabc7292b4b7dc5df879f0"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0bbc27abdf6aebfa1bce34cd92bd403070356f28b0ecb3198ff8a182791d58b9"}, + {file = "Cython-0.29.32-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cddc47ec746a08603037731f5d10aebf770ced08666100bd2cdcaf06a85d4d1b"}, + {file = "Cython-0.29.32-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca3065a1279456e81c615211d025ea11bfe4e19f0c5650b859868ca04b3fcbd"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d968ffc403d92addf20b68924d95428d523436adfd25cf505d427ed7ba3bee8b"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f3fd44cc362eee8ae569025f070d56208908916794b6ab21e139cea56470a2b3"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:b6da3063c5c476f5311fd76854abae6c315f1513ef7d7904deed2e774623bbb9"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:061e25151c38f2361bc790d3bcf7f9d9828a0b6a4d5afa56fbed3bd33fb2373a"}, + {file = "Cython-0.29.32-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f9944013588a3543fca795fffb0a070a31a243aa4f2d212f118aa95e69485831"}, + {file = "Cython-0.29.32-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:07d173d3289415bb496e72cb0ddd609961be08fe2968c39094d5712ffb78672b"}, + {file = "Cython-0.29.32-py2.py3-none-any.whl", hash = "sha256:eeb475eb6f0ccf6c039035eb4f0f928eb53ead88777e0a760eccb140ad90930b"}, + {file = "Cython-0.29.32.tar.gz", hash = "sha256:8733cf4758b79304f2a4e39ebfac5e92341bce47bcceb26c1254398b2f8c1af7"}, +] dateutils = [ {file = "dateutils-0.6.12-py2.py3-none-any.whl", hash = "sha256:f33b6ab430fa4166e7e9cb8b21ee9f6c9843c48df1a964466f52c79b2a8d53b3"}, {file = "dateutils-0.6.12.tar.gz", hash = "sha256:03dd90bcb21541bd4eb4b013637e4f1b5f944881c46cc6e4b67a6059e370e3f1"}, @@ -840,18 +1006,21 @@ dateutils = [ docopt = [ {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, ] -ecdsa = [] +ecdsa = [ + {file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"}, + {file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"}, +] flake8 = [ - {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, - {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, + {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, + {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, ] gitdb = [ {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, ] -gitpython = [ - {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, - {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, +GitPython = [ + {file = "GitPython-3.1.28-py3-none-any.whl", hash = "sha256:77bfbd299d8709f6af7e0c70840ef26e7aff7cf0c1ed53b42dd7fc3a310fcb02"}, + {file = "GitPython-3.1.28.tar.gz", hash = "sha256:6bd3451b8271132f099ceeaf581392eaf6c274af74bb06144307870479d0697c"}, ] h11 = [ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, @@ -866,8 +1035,8 @@ httpx = [ {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, ] idna = [ - {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, - {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -878,36 +1047,37 @@ isort = [ {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] lighthive = [ - {file = "lighthive-0.3.3.tar.gz", hash = "sha256:8933c970d8fe2201499ac988f8db656f0587ed79ca74f405ff8e8a855b478e08"}, + {file = "lighthive-0.4.0.tar.gz", hash = "sha256:2043a0728605459292fe13c526c32eaa85860e56338277193cb6979dc5cc7d93"}, ] mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] mypy = [ - {file = "mypy-0.950-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf9c261958a769a3bd38c3e133801ebcd284ffb734ea12d01457cb09eacf7d7b"}, - {file = "mypy-0.950-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5b5bd0ffb11b4aba2bb6d31b8643902c48f990cc92fda4e21afac658044f0c0"}, - {file = "mypy-0.950-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5e7647df0f8fc947388e6251d728189cfadb3b1e558407f93254e35abc026e22"}, - {file = "mypy-0.950-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eaff8156016487c1af5ffa5304c3e3fd183edcb412f3e9c72db349faf3f6e0eb"}, - {file = "mypy-0.950-cp310-cp310-win_amd64.whl", hash = "sha256:563514c7dc504698fb66bb1cf897657a173a496406f1866afae73ab5b3cdb334"}, - {file = "mypy-0.950-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dd4d670eee9610bf61c25c940e9ade2d0ed05eb44227275cce88701fee014b1f"}, - {file = "mypy-0.950-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca75ecf2783395ca3016a5e455cb322ba26b6d33b4b413fcdedfc632e67941dc"}, - {file = "mypy-0.950-cp36-cp36m-win_amd64.whl", hash = "sha256:6003de687c13196e8a1243a5e4bcce617d79b88f83ee6625437e335d89dfebe2"}, - {file = "mypy-0.950-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c653e4846f287051599ed8f4b3c044b80e540e88feec76b11044ddc5612ffed"}, - {file = "mypy-0.950-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e19736af56947addedce4674c0971e5dceef1b5ec7d667fe86bcd2b07f8f9075"}, - {file = "mypy-0.950-cp37-cp37m-win_amd64.whl", hash = "sha256:ef7beb2a3582eb7a9f37beaf38a28acfd801988cde688760aea9e6cc4832b10b"}, - {file = "mypy-0.950-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0112752a6ff07230f9ec2f71b0d3d4e088a910fdce454fdb6553e83ed0eced7d"}, - {file = "mypy-0.950-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee0a36edd332ed2c5208565ae6e3a7afc0eabb53f5327e281f2ef03a6bc7687a"}, - {file = "mypy-0.950-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77423570c04aca807508a492037abbd72b12a1fb25a385847d191cd50b2c9605"}, - {file = "mypy-0.950-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ce6a09042b6da16d773d2110e44f169683d8cc8687e79ec6d1181a72cb028d2"}, - {file = "mypy-0.950-cp38-cp38-win_amd64.whl", hash = "sha256:5b231afd6a6e951381b9ef09a1223b1feabe13625388db48a8690f8daa9b71ff"}, - {file = "mypy-0.950-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0384d9f3af49837baa92f559d3fa673e6d2652a16550a9ee07fc08c736f5e6f8"}, - {file = "mypy-0.950-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1fdeb0a0f64f2a874a4c1f5271f06e40e1e9779bf55f9567f149466fc7a55038"}, - {file = "mypy-0.950-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:61504b9a5ae166ba5ecfed9e93357fd51aa693d3d434b582a925338a2ff57fd2"}, - {file = "mypy-0.950-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a952b8bc0ae278fc6316e6384f67bb9a396eb30aced6ad034d3a76120ebcc519"}, - {file = "mypy-0.950-cp39-cp39-win_amd64.whl", hash = "sha256:eaea21d150fb26d7b4856766e7addcf929119dd19fc832b22e71d942835201ef"}, - {file = "mypy-0.950-py3-none-any.whl", hash = "sha256:a4d9898f46446bfb6405383b57b96737dcfd0a7f25b748e78ef3e8c576bba3cb"}, - {file = "mypy-0.950.tar.gz", hash = "sha256:1b333cfbca1762ff15808a0ef4f71b5d3eed8528b23ea1c3fb50543c867d68de"}, + {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, + {file = "mypy-0.982-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41fd1cf9bc0e1c19b9af13a6580ccb66c381a5ee2cf63ee5ebab747a4badeba3"}, + {file = "mypy-0.982-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f793e3dd95e166b66d50e7b63e69e58e88643d80a3dcc3bcd81368e0478b089c"}, + {file = "mypy-0.982-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86ebe67adf4d021b28c3f547da6aa2cce660b57f0432617af2cca932d4d378a6"}, + {file = "mypy-0.982-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:175f292f649a3af7082fe36620369ffc4661a71005aa9f8297ea473df5772046"}, + {file = "mypy-0.982-cp310-cp310-win_amd64.whl", hash = "sha256:8ee8c2472e96beb1045e9081de8e92f295b89ac10c4109afdf3a23ad6e644f3e"}, + {file = "mypy-0.982-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58f27ebafe726a8e5ccb58d896451dd9a662a511a3188ff6a8a6a919142ecc20"}, + {file = "mypy-0.982-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6af646bd46f10d53834a8e8983e130e47d8ab2d4b7a97363e35b24e1d588947"}, + {file = "mypy-0.982-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7aeaa763c7ab86d5b66ff27f68493d672e44c8099af636d433a7f3fa5596d40"}, + {file = "mypy-0.982-cp37-cp37m-win_amd64.whl", hash = "sha256:724d36be56444f569c20a629d1d4ee0cb0ad666078d59bb84f8f887952511ca1"}, + {file = "mypy-0.982-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14d53cdd4cf93765aa747a7399f0961a365bcddf7855d9cef6306fa41de01c24"}, + {file = "mypy-0.982-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26ae64555d480ad4b32a267d10cab7aec92ff44de35a7cd95b2b7cb8e64ebe3e"}, + {file = "mypy-0.982-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6389af3e204975d6658de4fb8ac16f58c14e1bacc6142fee86d1b5b26aa52bda"}, + {file = "mypy-0.982-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b35ce03a289480d6544aac85fa3674f493f323d80ea7226410ed065cd46f206"}, + {file = "mypy-0.982-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6e564f035d25c99fd2b863e13049744d96bd1947e3d3d2f16f5828864506763"}, + {file = "mypy-0.982-cp38-cp38-win_amd64.whl", hash = "sha256:cebca7fd333f90b61b3ef7f217ff75ce2e287482206ef4a8b18f32b49927b1a2"}, + {file = "mypy-0.982-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a705a93670c8b74769496280d2fe6cd59961506c64f329bb179970ff1d24f9f8"}, + {file = "mypy-0.982-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75838c649290d83a2b83a88288c1eb60fe7a05b36d46cbea9d22efc790002146"}, + {file = "mypy-0.982-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91781eff1f3f2607519c8b0e8518aad8498af1419e8442d5d0afb108059881fc"}, + {file = "mypy-0.982-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa97b9ddd1dd9901a22a879491dbb951b5dec75c3b90032e2baa7336777363b"}, + {file = "mypy-0.982-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a692a8e7d07abe5f4b2dd32d731812a0175626a90a223d4b58f10f458747dd8a"}, + {file = "mypy-0.982-cp39-cp39-win_amd64.whl", hash = "sha256:eb7a068e503be3543c4bd329c994103874fa543c1727ba5288393c21d912d795"}, + {file = "mypy-0.982-py3-none-any.whl", hash = "sha256:1021c241e8b6e1ca5a47e4d52601274ac078a89845cfde66c6d5f769819ffa1d"}, + {file = "mypy-0.982.tar.gz", hash = "sha256:85f7a343542dc8b1ed0a888cdd34dca56462654ef23aa673907305b260b3d746"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -917,14 +1087,17 @@ packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] -patch-env = [] +patch-env = [ + {file = "patch_env-1.0.0-py2.py3-none-any.whl", hash = "sha256:f12d54f8451f1347d6040b3167d29e1c60cdbc56dcf5282c28cc7e24f76393b7"}, + {file = "patch_env-1.0.0.tar.gz", hash = "sha256:7c9bf612a3ee78eb9f0f7ab2d1c62a85626987ef8c2441c5fb053005f199d4d4"}, +] pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, + {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, + {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, ] pbr = [ - {file = "pbr-5.9.0-py2.py3-none-any.whl", hash = "sha256:e547125940bcc052856ded43be8e101f63828c2d94239ffbe2b327ba3d5ccf0a"}, - {file = "pbr-5.9.0.tar.gz", hash = "sha256:e8dca2f4b43560edef58813969f52a56cef023146cbb8931626db80e6c1c4308"}, + {file = "pbr-5.10.0-py2.py3-none-any.whl", hash = "sha256:da3e18aac0a3c003e9eea1a81bd23e5a3a75d745670dcf736317b7d966887fdf"}, + {file = "pbr-5.10.0.tar.gz", hash = "sha256:cfcc4ff8e698256fc17ea3ff796478b050852585aa5bae79ecd05b2ab7b39b9a"}, ] platformdirs = [ {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, @@ -939,53 +1112,54 @@ py = [ {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pycodestyle = [ - {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, - {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, + {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, + {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, ] pycparser = [ {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] pydantic = [ - {file = "pydantic-1.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8098a724c2784bf03e8070993f6d46aa2eeca031f8d8a048dff277703e6e193"}, - {file = "pydantic-1.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c320c64dd876e45254bdd350f0179da737463eea41c43bacbee9d8c9d1021f11"}, - {file = "pydantic-1.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18f3e912f9ad1bdec27fb06b8198a2ccc32f201e24174cec1b3424dda605a310"}, - {file = "pydantic-1.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c11951b404e08b01b151222a1cb1a9f0a860a8153ce8334149ab9199cd198131"}, - {file = "pydantic-1.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8bc541a405423ce0e51c19f637050acdbdf8feca34150e0d17f675e72d119580"}, - {file = "pydantic-1.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e565a785233c2d03724c4dc55464559639b1ba9ecf091288dd47ad9c629433bd"}, - {file = "pydantic-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a4a88dcd6ff8fd47c18b3a3709a89adb39a6373f4482e04c1b765045c7e282fd"}, - {file = "pydantic-1.9.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:447d5521575f18e18240906beadc58551e97ec98142266e521c34968c76c8761"}, - {file = "pydantic-1.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:985ceb5d0a86fcaa61e45781e567a59baa0da292d5ed2e490d612d0de5796918"}, - {file = "pydantic-1.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059b6c1795170809103a1538255883e1983e5b831faea6558ef873d4955b4a74"}, - {file = "pydantic-1.9.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d12f96b5b64bec3f43c8e82b4aab7599d0157f11c798c9f9c528a72b9e0b339a"}, - {file = "pydantic-1.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ae72f8098acb368d877b210ebe02ba12585e77bd0db78ac04a1ee9b9f5dd2166"}, - {file = "pydantic-1.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:79b485767c13788ee314669008d01f9ef3bc05db9ea3298f6a50d3ef596a154b"}, - {file = "pydantic-1.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:494f7c8537f0c02b740c229af4cb47c0d39840b829ecdcfc93d91dcbb0779892"}, - {file = "pydantic-1.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0f047e11febe5c3198ed346b507e1d010330d56ad615a7e0a89fae604065a0e"}, - {file = "pydantic-1.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:969dd06110cb780da01336b281f53e2e7eb3a482831df441fb65dd30403f4608"}, - {file = "pydantic-1.9.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:177071dfc0df6248fd22b43036f936cfe2508077a72af0933d0c1fa269b18537"}, - {file = "pydantic-1.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9bcf8b6e011be08fb729d110f3e22e654a50f8a826b0575c7196616780683380"}, - {file = "pydantic-1.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a955260d47f03df08acf45689bd163ed9df82c0e0124beb4251b1290fa7ae728"}, - {file = "pydantic-1.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9ce157d979f742a915b75f792dbd6aa63b8eccaf46a1005ba03aa8a986bde34a"}, - {file = "pydantic-1.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0bf07cab5b279859c253d26a9194a8906e6f4a210063b84b433cf90a569de0c1"}, - {file = "pydantic-1.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d93d4e95eacd313d2c765ebe40d49ca9dd2ed90e5b37d0d421c597af830c195"}, - {file = "pydantic-1.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1542636a39c4892c4f4fa6270696902acb186a9aaeac6f6cf92ce6ae2e88564b"}, - {file = "pydantic-1.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a9af62e9b5b9bc67b2a195ebc2c2662fdf498a822d62f902bf27cccb52dbbf49"}, - {file = "pydantic-1.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fe4670cb32ea98ffbf5a1262f14c3e102cccd92b1869df3bb09538158ba90fe6"}, - {file = "pydantic-1.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:9f659a5ee95c8baa2436d392267988fd0f43eb774e5eb8739252e5a7e9cf07e0"}, - {file = "pydantic-1.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b83ba3825bc91dfa989d4eed76865e71aea3a6ca1388b59fc801ee04c4d8d0d6"}, - {file = "pydantic-1.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1dd8fecbad028cd89d04a46688d2fcc14423e8a196d5b0a5c65105664901f810"}, - {file = "pydantic-1.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02eefd7087268b711a3ff4db528e9916ac9aa18616da7bca69c1871d0b7a091f"}, - {file = "pydantic-1.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7eb57ba90929bac0b6cc2af2373893d80ac559adda6933e562dcfb375029acee"}, - {file = "pydantic-1.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4ce9ae9e91f46c344bec3b03d6ee9612802682c1551aaf627ad24045ce090761"}, - {file = "pydantic-1.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72ccb318bf0c9ab97fc04c10c37683d9eea952ed526707fabf9ac5ae59b701fd"}, - {file = "pydantic-1.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b6760b08b7c395975d893e0b814a11cf011ebb24f7d869e7118f5a339a82e1"}, - {file = "pydantic-1.9.1-py3-none-any.whl", hash = "sha256:4988c0f13c42bfa9ddd2fe2f569c9d54646ce84adc5de84228cfe83396f3bd58"}, - {file = "pydantic-1.9.1.tar.gz", hash = "sha256:1ed987c3ff29fff7fd8c3ea3a3ea877ad310aae2ef9889a119e22d3f2db0691a"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, + {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, + {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, + {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, + {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, + {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, + {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, + {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, + {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, ] pyflakes = [ - {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, - {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, + {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, + {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, @@ -995,19 +1169,21 @@ pypytools = [ {file = "pypytools-0.6.2.tar.gz", hash = "sha256:a140c053e4d1c0bae835f40662eb0040a75190771acf2b2a8832dfa7beefe529"}, ] pytest = [ - {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, - {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, + {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, + {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, ] pytest-asyncio = [ - {file = "pytest-asyncio-0.18.3.tar.gz", hash = "sha256:7659bdb0a9eb9c6e3ef992eef11a2b3e69697800ad02fb06374a210d85b29f91"}, - {file = "pytest_asyncio-0.18.3-1-py3-none-any.whl", hash = "sha256:16cf40bdf2b4fb7fc8e4b82bd05ce3fbcd454cbf7b92afc445fe299dabb88213"}, - {file = "pytest_asyncio-0.18.3-py3-none-any.whl", hash = "sha256:8fafa6c52161addfd41ee7ab35f11836c5a16ec208f93ee388f752bea3493a84"}, + {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, + {file = "pytest_asyncio-0.19.0-py3-none-any.whl", hash = "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa"}, ] 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"}, + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] +pytest-mock = [ + {file = "pytest-mock-3.10.0.tar.gz", hash = "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f"}, + {file = "pytest_mock-3.10.0-py3-none-any.whl", hash = "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b"}, ] -pytest-mock = [] pytest-timeout = [ {file = "pytest-timeout-2.1.0.tar.gz", hash = "sha256:c07ca07404c612f8abbe22294b23c368e2e5104b521c1790195561f37e1ac3d9"}, {file = "pytest_timeout-2.1.0-py3-none-any.whl", hash = "sha256:f6f50101443ce70ad325ceb4473c4255e9d74e3c7cd0ef827309dfa4c0d975c6"}, @@ -1017,10 +1193,10 @@ python-dateutil = [ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] pytz = [ - {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, - {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, + {file = "pytz-2022.4-py2.py3-none-any.whl", hash = "sha256:2c0784747071402c6e99f0bafdb7da0fa22645f06554c7ae06bf6358897e9c91"}, + {file = "pytz-2022.4.tar.gz", hash = "sha256:48ce799d83b6f8aab2020e369b627446696619e79645419610b9facd909b3174"}, ] -pyyaml = [ +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"}, @@ -1028,6 +1204,13 @@ pyyaml = [ {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-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, {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"}, @@ -1056,55 +1239,85 @@ pyyaml = [ {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, ] pyzmq = [ - {file = "pyzmq-22.3.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:6b217b8f9dfb6628f74b94bdaf9f7408708cb02167d644edca33f38746ca12dd"}, - {file = "pyzmq-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2841997a0d85b998cbafecb4183caf51fd19c4357075dfd33eb7efea57e4c149"}, - {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f89468059ebc519a7acde1ee50b779019535db8dcf9b8c162ef669257fef7a93"}, - {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea12133df25e3a6918718fbb9a510c6ee5d3fdd5a346320421aac3882f4feeea"}, - {file = "pyzmq-22.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c532fd68b93998aab92356be280deec5de8f8fe59cd28763d2cc8a58747b7f"}, - {file = "pyzmq-22.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f907c7359ce8bf7f7e63c82f75ad0223384105f5126f313400b7e8004d9b33c3"}, - {file = "pyzmq-22.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:902319cfe23366595d3fa769b5b751e6ee6750a0a64c5d9f757d624b2ac3519e"}, - {file = "pyzmq-22.3.0-cp310-cp310-win32.whl", hash = "sha256:67db33bea0a29d03e6eeec55a8190e033318cee3cbc732ba8fd939617cbf762d"}, - {file = "pyzmq-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:7661fc1d5cb73481cf710a1418a4e1e301ed7d5d924f91c67ba84b2a1b89defd"}, - {file = "pyzmq-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79244b9e97948eaf38695f4b8e6fc63b14b78cc37f403c6642ba555517ac1268"}, - {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab888624ed68930442a3f3b0b921ad7439c51ba122dbc8c386e6487a658e4a4e"}, - {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18cd854b423fce44951c3a4d3e686bac8f1243d954f579e120a1714096637cc0"}, - {file = "pyzmq-22.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:de8df0684398bd74ad160afdc2a118ca28384ac6f5e234eb0508858d8d2d9364"}, - {file = "pyzmq-22.3.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:62bcade20813796c426409a3e7423862d50ff0639f5a2a95be4b85b09a618666"}, - {file = "pyzmq-22.3.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ea5a79e808baef98c48c884effce05c31a0698c1057de8fc1c688891043c1ce1"}, - {file = "pyzmq-22.3.0-cp36-cp36m-win32.whl", hash = "sha256:3c1895c95be92600233e476fe283f042e71cf8f0b938aabf21b7aafa62a8dac9"}, - {file = "pyzmq-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:851977788b9caa8ed011f5f643d3ee8653af02c5fc723fa350db5125abf2be7b"}, - {file = "pyzmq-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b4ebed0977f92320f6686c96e9e8dd29eed199eb8d066936bac991afc37cbb70"}, - {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42abddebe2c6a35180ca549fadc7228d23c1e1f76167c5ebc8a936b5804ea2df"}, - {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1e41b32d6f7f9c26bc731a8b529ff592f31fc8b6ef2be9fa74abd05c8a342d7"}, - {file = "pyzmq-22.3.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:be4e0f229cf3a71f9ecd633566bd6f80d9fa6afaaff5489492be63fe459ef98c"}, - {file = "pyzmq-22.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08c4e315a76ef26eb833511ebf3fa87d182152adf43dedee8d79f998a2162a0b"}, - {file = "pyzmq-22.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:badb868fff14cfd0e200eaa845887b1011146a7d26d579aaa7f966c203736b92"}, - {file = "pyzmq-22.3.0-cp37-cp37m-win32.whl", hash = "sha256:7c58f598d9fcc52772b89a92d72bf8829c12d09746a6d2c724c5b30076c1f11d"}, - {file = "pyzmq-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2b97502c16a5ec611cd52410bdfaab264997c627a46b0f98d3f666227fd1ea2d"}, - {file = "pyzmq-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d728b08448e5ac3e4d886b165385a262883c34b84a7fe1166277fe675e1c197a"}, - {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:480b9931bfb08bf8b094edd4836271d4d6b44150da051547d8c7113bf947a8b0"}, - {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7dc09198e4073e6015d9a8ea093fc348d4e59de49382476940c3dd9ae156fba8"}, - {file = "pyzmq-22.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ca6cd58f62a2751728016d40082008d3b3412a7f28ddfb4a2f0d3c130f69e74"}, - {file = "pyzmq-22.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:468bd59a588e276961a918a3060948ae68f6ff5a7fa10bb2f9160c18fe341067"}, - {file = "pyzmq-22.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c88fa7410e9fc471e0858638f403739ee869924dd8e4ae26748496466e27ac59"}, - {file = "pyzmq-22.3.0-cp38-cp38-win32.whl", hash = "sha256:c0f84360dcca3481e8674393bdf931f9f10470988f87311b19d23cda869bb6b7"}, - {file = "pyzmq-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:f762442bab706fd874064ca218b33a1d8e40d4938e96c24dafd9b12e28017f45"}, - {file = "pyzmq-22.3.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:954e73c9cd4d6ae319f1c936ad159072b6d356a92dcbbabfd6e6204b9a79d356"}, - {file = "pyzmq-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f43b4a2e6218371dd4f41e547bd919ceeb6ebf4abf31a7a0669cd11cd91ea973"}, - {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:acebba1a23fb9d72b42471c3771b6f2f18dcd46df77482612054bd45c07dfa36"}, - {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cf98fd7a6c8aaa08dbc699ffae33fd71175696d78028281bc7b832b26f00ca57"}, - {file = "pyzmq-22.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d072f7dfbdb184f0786d63bda26e8a0882041b1e393fbe98940395f7fab4c5e2"}, - {file = "pyzmq-22.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:53f4fd13976789ffafedd4d46f954c7bb01146121812b72b4ddca286034df966"}, - {file = "pyzmq-22.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1b5d457acbadcf8b27561deeaa386b0217f47626b29672fa7bd31deb6e91e1b"}, - {file = "pyzmq-22.3.0-cp39-cp39-win32.whl", hash = "sha256:e6a02cf7271ee94674a44f4e62aa061d2d049001c844657740e156596298b70b"}, - {file = "pyzmq-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d3dcb5548ead4f1123851a5ced467791f6986d68c656bc63bfff1bf9e36671e2"}, - {file = "pyzmq-22.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3a4c9886d61d386b2b493377d980f502186cd71d501fffdba52bd2a0880cef4f"}, - {file = "pyzmq-22.3.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:80e043a89c6cadefd3a0712f8a1322038e819ebe9dbac7eca3bce1721bcb63bf"}, - {file = "pyzmq-22.3.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1621e7a2af72cced1f6ec8ca8ca91d0f76ac236ab2e8828ac8fe909512d566cb"}, - {file = "pyzmq-22.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d6157793719de168b199194f6b6173f0ccd3bf3499e6870fac17086072e39115"}, - {file = "pyzmq-22.3.0.tar.gz", hash = "sha256:8eddc033e716f8c91c6a2112f0a8ebc5e00532b4a6ae1eb0ccc48e027f9c671c"}, -] -requests = [] + {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:28b119ba97129d3001673a697b7cce47fe6de1f7255d104c2f01108a5179a066"}, + {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bcbebd369493d68162cddb74a9c1fcebd139dfbb7ddb23d8f8e43e6c87bac3a6"}, + {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae61446166983c663cee42c852ed63899e43e484abf080089f771df4b9d272ef"}, + {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f7ac99b15270db8d53f28c3c7b968612993a90a5cf359da354efe96f5372b4"}, + {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca7c3956b03b7663fac4d150f5e6d4f6f38b2462c1e9afd83bcf7019f17913"}, + {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8c78bfe20d4c890cb5580a3b9290f700c570e167d4cdcc55feec07030297a5e3"}, + {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48f721f070726cd2a6e44f3c33f8ee4b24188e4b816e6dd8ba542c8c3bb5b246"}, + {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afe1f3bc486d0ce40abb0a0c9adb39aed3bbac36ebdc596487b0cceba55c21c1"}, + {file = "pyzmq-24.0.1-cp310-cp310-win32.whl", hash = "sha256:3e6192dbcefaaa52ed81be88525a54a445f4b4fe2fffcae7fe40ebb58bd06bfd"}, + {file = "pyzmq-24.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:86de64468cad9c6d269f32a6390e210ca5ada568c7a55de8e681ca3b897bb340"}, + {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:838812c65ed5f7c2bd11f7b098d2e5d01685a3f6d1f82849423b570bae698c00"}, + {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfb992dbcd88d8254471760879d48fb20836d91baa90f181c957122f9592b3dc"}, + {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7abddb2bd5489d30ffeb4b93a428130886c171b4d355ccd226e83254fcb6b9ef"}, + {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94010bd61bc168c103a5b3b0f56ed3b616688192db7cd5b1d626e49f28ff51b3"}, + {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8242543c522d84d033fe79be04cb559b80d7eb98ad81b137ff7e0a9020f00ace"}, + {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ccb94342d13e3bf3ffa6e62f95b5e3f0bc6bfa94558cb37f4b3d09d6feb536ff"}, + {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6640f83df0ae4ae1104d4c62b77e9ef39be85ebe53f636388707d532bee2b7b8"}, + {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a180dbd5ea5d47c2d3b716d5c19cc3fb162d1c8db93b21a1295d69585bfddac1"}, + {file = "pyzmq-24.0.1-cp311-cp311-win32.whl", hash = "sha256:624321120f7e60336be8ec74a172ae7fba5c3ed5bf787cc85f7e9986c9e0ebc2"}, + {file = "pyzmq-24.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1724117bae69e091309ffb8255412c4651d3f6355560d9af312d547f6c5bc8b8"}, + {file = "pyzmq-24.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:15975747462ec49fdc863af906bab87c43b2491403ab37a6d88410635786b0f4"}, + {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b947e264f0e77d30dcbccbb00f49f900b204b922eb0c3a9f0afd61aaa1cedc3d"}, + {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ec91f1bad66f3ee8c6deb65fa1fe418e8ad803efedd69c35f3b5502f43bd1dc"}, + {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db03704b3506455d86ec72c3358a779e9b1d07b61220dfb43702b7b668edcd0d"}, + {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e7e66b4e403c2836ac74f26c4b65d8ac0ca1eef41dfcac2d013b7482befaad83"}, + {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7a23ccc1083c260fa9685c93e3b170baba45aeed4b524deb3f426b0c40c11639"}, + {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fa0ae3275ef706c0309556061185dd0e4c4cd3b7d6f67ae617e4e677c7a41e2e"}, + {file = "pyzmq-24.0.1-cp36-cp36m-win32.whl", hash = "sha256:f01de4ec083daebf210531e2cca3bdb1608dbbbe00a9723e261d92087a1f6ebc"}, + {file = "pyzmq-24.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:de4217b9eb8b541cf2b7fde4401ce9d9a411cc0af85d410f9d6f4333f43640be"}, + {file = "pyzmq-24.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:78068e8678ca023594e4a0ab558905c1033b2d3e806a0ad9e3094e231e115a33"}, + {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77c2713faf25a953c69cf0f723d1b7dd83827b0834e6c41e3fb3bbc6765914a1"}, + {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bb4af15f305056e95ca1bd086239b9ebc6ad55e9f49076d27d80027f72752f6"}, + {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0f14cffd32e9c4c73da66db97853a6aeceaac34acdc0fae9e5bbc9370281864c"}, + {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0108358dab8c6b27ff6b985c2af4b12665c1bc659648284153ee501000f5c107"}, + {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d66689e840e75221b0b290b0befa86f059fb35e1ee6443bce51516d4d61b6b99"}, + {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae08ac90aa8fa14caafc7a6251bd218bf6dac518b7bff09caaa5e781119ba3f2"}, + {file = "pyzmq-24.0.1-cp37-cp37m-win32.whl", hash = "sha256:8421aa8c9b45ea608c205db9e1c0c855c7e54d0e9c2c2f337ce024f6843cab3b"}, + {file = "pyzmq-24.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54d8b9c5e288362ec8595c1d98666d36f2070fd0c2f76e2b3c60fbad9bd76227"}, + {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:acbd0a6d61cc954b9f535daaa9ec26b0a60a0d4353c5f7c1438ebc88a359a47e"}, + {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:47b11a729d61a47df56346283a4a800fa379ae6a85870d5a2e1e4956c828eedc"}, + {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abe6eb10122f0d746a0d510c2039ae8edb27bc9af29f6d1b05a66cc2401353ff"}, + {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:07bec1a1b22dacf718f2c0e71b49600bb6a31a88f06527dfd0b5aababe3fa3f7"}, + {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d945a85b70da97ae86113faf9f1b9294efe66bd4a5d6f82f2676d567338b66"}, + {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7928bb7580736ffac5baf814097be342ba08d3cfdfb48e52773ec959572287"}, + {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b946da90dc2799bcafa682692c1d2139b2a96ec3c24fa9fc6f5b0da782675330"}, + {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c8840f064b1fb377cffd3efeaad2b190c14d4c8da02316dae07571252d20b31f"}, + {file = "pyzmq-24.0.1-cp38-cp38-win32.whl", hash = "sha256:4854f9edc5208f63f0841c0c667260ae8d6846cfa233c479e29fdc85d42ebd58"}, + {file = "pyzmq-24.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:42d4f97b9795a7aafa152a36fe2ad44549b83a743fd3e77011136def512e6c2a"}, + {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:52afb0ac962963fff30cf1be775bc51ae083ef4c1e354266ab20e5382057dd62"}, + {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bad8210ad4df68c44ff3685cca3cda448ee46e20d13edcff8909eba6ec01ca4"}, + {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dabf1a05318d95b1537fd61d9330ef4313ea1216eea128a17615038859da3b3b"}, + {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5bd3d7dfd9cd058eb68d9a905dec854f86649f64d4ddf21f3ec289341386c44b"}, + {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8012bce6836d3f20a6c9599f81dfa945f433dab4dbd0c4917a6fb1f998ab33d"}, + {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c31805d2c8ade9b11feca4674eee2b9cce1fec3e8ddb7bbdd961a09dc76a80ea"}, + {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3104f4b084ad5d9c0cb87445cc8cfd96bba710bef4a66c2674910127044df209"}, + {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:df0841f94928f8af9c7a1f0aaaffba1fb74607af023a152f59379c01c53aee58"}, + {file = "pyzmq-24.0.1-cp39-cp39-win32.whl", hash = "sha256:a435ef8a3bd95c8a2d316d6e0ff70d0db524f6037411652803e118871d703333"}, + {file = "pyzmq-24.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2032d9cb994ce3b4cba2b8dfae08c7e25bc14ba484c770d4d3be33c27de8c45b"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bb5635c851eef3a7a54becde6da99485eecf7d068bd885ac8e6d173c4ecd68b0"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:83ea1a398f192957cb986d9206ce229efe0ee75e3c6635baff53ddf39bd718d5"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:941fab0073f0a54dc33d1a0460cb04e0d85893cb0c5e1476c785000f8b359409"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8f482c44ccb5884bf3f638f29bea0f8dc68c97e38b2061769c4cb697f6140d"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:613010b5d17906c4367609e6f52e9a2595e35d5cc27d36ff3f1b6fa6e954d944"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:65c94410b5a8355cfcf12fd600a313efee46ce96a09e911ea92cf2acf6708804"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:20e7eeb1166087db636c06cae04a1ef59298627f56fb17da10528ab52a14c87f"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2712aee7b3834ace51738c15d9ee152cc5a98dc7d57dd93300461b792ab7b43"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7c280185c4da99e0cc06c63bdf91f5b0b71deb70d8717f0ab870a43e376db8"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:858375573c9225cc8e5b49bfac846a77b696b8d5e815711b8d4ba3141e6e8879"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:80093b595921eed1a2cead546a683b9e2ae7f4a4592bb2ab22f70d30174f003a"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f3f3154fde2b1ff3aa7b4f9326347ebc89c8ef425ca1db8f665175e6d3bd42f"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb756147314430bee5d10919b8493c0ccb109ddb7f5dfd2fcd7441266a25b75"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e706bac34e9f50779cb8c39f10b53a4d15aebb97235643d3112ac20bd577b4"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:687700f8371643916a1d2c61f3fdaa630407dd205c38afff936545d7b7466066"}, + {file = "pyzmq-24.0.1.tar.gz", hash = "sha256:216f5d7dbb67166759e59b0479bca82b8acf9bed6015b526b8eb10143fb08e77"}, +] +requests = [ + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, +] rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, @@ -1113,7 +1326,10 @@ rfc3987 = [ {file = "rfc3987-1.3.8-py2.py3-none-any.whl", hash = "sha256:10702b1e51e5658843460b189b185c0366d2cf4cff716f13111b0ea9fd2dce53"}, {file = "rfc3987-1.3.8.tar.gz", hash = "sha256:d3c4d257a560d544e9826b38bc81db676890c79ab9d7ac92b39c7a253d5ca733"}, ] -shellingham = [] +shellingham = [ + {file = "shellingham-1.5.0-py2.py3-none-any.whl", hash = "sha256:a8f02ba61b69baaa13facdba62908ca8690a94b8119b69f5ec5873ea85f7391b"}, + {file = "shellingham-1.5.0.tar.gz", hash = "sha256:72fb7f5c63103ca2cb91b23dee0c71fe8ad6fbfd46418ef17dbe40db51592dad"}, +] single-source = [ {file = "single-source-0.3.0.tar.gz", hash = "sha256:b12705af958ca99d56ea9ce40bd9cc749378f4fe7ad03b1f9067e29daceef27d"}, {file = "single_source-0.3.0-py3-none-any.whl", hash = "sha256:7bc87168ced50f638b6ab0cda4cc1ce9e80ee0e1220014397050d336d021a597"}, @@ -1127,10 +1343,13 @@ smmap = [ {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, ] sniffio = [ - {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, - {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] +stevedore = [ + {file = "stevedore-4.0.0-py3-none-any.whl", hash = "sha256:87e4d27fe96d0d7e4fc24f0cbe3463baae4ec51e81d95fbe60d2474636e0c7d8"}, + {file = "stevedore-4.0.0.tar.gz", hash = "sha256:f82cc99a1ff552310d19c379827c2c64dd9f85a38bcd5559db2470161867b786"}, ] -stevedore = [] tomli = [ {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, @@ -1143,5 +1362,11 @@ typer-cli = [ {file = "typer-cli-0.0.12.tar.gz", hash = "sha256:d2c4a7a5c0326c20fb0970eed3c2173f76ba6b8b33d9bbece3a3dd91d673f096"}, {file = "typer_cli-0.0.12-py3-none-any.whl", hash = "sha256:f9b810d4fbdb750b28ceaa5fd8f737db596570418ae092e6d54a64d378e843ca"}, ] -typing-extensions = [] -urllib3 = [] +typing-extensions = [ + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, +] +urllib3 = [ + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, +] diff --git a/pyproject.toml b/pyproject.toml index bcd6e65..13b396b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "podping-hivewriter" -version = "1.2.6" +version = "1.2.7" license = "MIT" authors = ["Alecks Gates ", "Brian of London "] maintainers = ["Alecks Gates ", "Brian of London "] @@ -22,7 +22,7 @@ include = ["src/podping_hivewriter/schema/*.py", "src/podping_hivewriter/schema/ [tool.poetry.dependencies] python = "^3.8" -pyzmq = "^22.1.0" +pyzmq = "^24.0.1" cffi = "^1.14.5" pydantic = "^1.9.0" single-source = "^0.3.0" @@ -30,19 +30,19 @@ rfc3987 = "^1.3.8" asgiref = "^3.5" typer = {extras = ["all"], version = "^0.3.2"} capnpy = "^0.9.0" -lighthive = "^0.3.0" +lighthive = "^0.4.0" [tool.poetry.dev-dependencies] black = "^21.5b2" isort = "^5.8.0" pytest = "^7.1.2" -pytest-cov = "^3.0.0" -pytest-asyncio = "^0.18.3" +pytest-cov = "^4.0.0" +pytest-asyncio = "^0.19.0" bandit = "^1.7.4" pytest-timeout = "^2.0.2" typer-cli = "^0.0.12" -flake8 = "^4.0.1" -mypy = "^0.950" +flake8 = "^5.0.4" +mypy = "^0.982" patch-env = "^1.0.0" pytest-mock = "^3.8.2" @@ -67,4 +67,8 @@ multi_line_output = 3 [tool.pytest.ini_options] testpaths = [ "tests", -] \ No newline at end of file +] +log_cli = true +log_cli_level = "INFO" +log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)" +log_cli_date_format = "%Y-%m-%d %H:%M:%S" \ No newline at end of file diff --git a/setup.py b/setup.py index 7ba3eb9..172692c 100644 --- a/setup.py +++ b/setup.py @@ -16,20 +16,20 @@ "asgiref>=3.5,<4.0", "capnpy>=0.9.0,<0.10.0", "cffi>=1.14.5,<2.0.0", - "lighthive>=0.3.0,<0.4.0", + "lighthive>=0.4.0,<0.5.0", "pydantic>=1.9.0,<2.0.0", "rfc3987>=1.3.8,<2.0.0", "single-source>=0.3.0,<0.4.0", "typer[all]>=0.3.2,<0.4.0", ] -extras_require = {"server": ["pyzmq>=22.1.0,<23.0.0"]} +extras_require = {"server": ["pyzmq>=24.0.1,<25.0.0"]} entry_points = {"console_scripts": ["podping = podping_hivewriter.cli.podping:app"]} setup_kwargs = { "name": "podping-hivewriter", - "version": "1.2.6", + "version": "1.2.7", "description": "This is a tool used to submit RFC 3987-compliant International Resource Identifiers as a Podping notification on the Hive blockchain.", "long_description": "# podping-hivewriter\nThe Hive writer component of Podping. You will need a Hive account, see section [Hive account and Authorization](#hive-account) below.\n\n## What is Podping?\n\nPodping is a mechanism of using decentralized communication to relay notification of updates of RSS feeds that use The Podcast Namespace. It does so by supplying minimum relevant metadata to consumers to be able to make efficient and actionable decisions, allowing them to decide what to do with given RSS feeds without parsing them ahead of time.\n\n*This* project provides a standardized way of posting a \"podping\" specifically to the Hive blockcahin.\n\n## Running podping-hivewriter\n\nThe project has two modes of running: `write` mode and `server` mode.\n\n`write` mode is primarily useful for people with a very small number of feeds to publish updates for relatively infrequently (i.e. a few times a day or less).\n\n`server` mode is for hosts (or other services like the Podcast Index's [podping.cloud](https://podping.cloud/)) who publish updates for a significant amount of feeds on a regular basis. Not that the average small-time podcast can't run it, but it's overkill. This mode is for efficiency only, as the `server` will batch process feeds as they come in to make the most use of the Hive blockchain.\n\nSee the dedicated [CLI docs](CLI.md) for more information on configuration options, including environment variables.\n\n### Container\n\nThe container images are hosted on [Docker Hub](https://hub.docker.com/r/podcastindexorg/podping-hivewriter). Images are currently based on Debian bullseye-based PyPy 3.8 with the following architectures: `amd64`\n\nThese images can be run in either `write` or `server` mode and is likely the easiest option for users who do not have experience installing Python packages.\n\n#### Command Line\n\nRunning in `write` mode with command line options, like `--dry-run` for example, add them with the full podping command.\nSettings can also be passed with the `-e` option for Docker. Note, we leave out `-p 9999:9999` here because we're not running the server.\n\n```shell\ndocker run --rm \\\n -e PODPING_HIVE_ACCOUNT= \\\n -e PODPING_HIVE_POSTING_KEY= \\\n docker.io/podcastindexorg/podping-hivewriter \\\n --dry-run write https://www.example.com/feed.xml\n```\n\nRun in `server` mode, passing local port 9999 to port 9999 in the container.\nENV variables can be passed to docker with `--env-file` option after modifying the `.env.EXAMPLE` file and renaming it to `.env`\n\n```shell\ndocker run --rm -p 9999:9999 --env-file .env --name podping docker.io/podcastindexorg/podping-hivewriter\n```\n\nAs another example for running in `server` mode, to run in *detached* mode, note the `-d` in the `docker run` options. Also note that `write` or `server` must come *after* the command line options for `podping`:\n```shell\ndocker run --rm -d \\\n -p 9999:9999 --env-file .env \\\n --name podping \\\n docker.io/podcastindexorg/podping-hivewriter \\\n --livetest server\n```\n\nOne running you can view and follow the live output with:\n```shell\ndocker logs podping -f\n```\n\nSee the [CLI docs](https://github.com/Podcastindex-org/podping-hivewriter/blob/main/CLI.md) for default values.\n\n\n#### docker-compose\n\n```yaml\nversion: '2.0'\nservices:\n podping-hivewriter:\n image: docker.io/podcastindexorg/podping-hivewriter\n restart: always\n ports:\n - \"9999:9999\"\n environment:\n - PODPING_HIVE_ACCOUNT=\n - PODPING_HIVE_POSTING_KEY=\n - PODPING_LISTEN_IP=0.0.0.0\n - PODPING_LISTEN_PORT=9999\n - PODPING_LIVETEST=false\n - PODPING_DRY_RUN=false\n - PODPING_STATUS=true\n - PODPING_IGNORE_CONFIG_UPDATES=false\n - PODPING_I_KNOW_WHAT_IM_DOING=false\n - PODPING_DEBUG=false\n```\n\nAssuming you just copy-pasted without reading, the above will fail at first. As noted in the [server command documentation](https://github.com/Podcastindex-org/podping-hivewriter/blob/main/CLI.md#podping-server):\n\n>WARNING: DO NOT run this on a publicly accessible host. There currently is NO authentication required to submit to the server. Set to * or 0.0.0.0 for all interfaces.\n\nAs all Docker installations vary, we set `0.0.0.0` as the listen IP for connectivity. This doesn't affect the IP address docker listens on when we tell it to pass port `9999` through to the container. If you understand the consequences of this, set `PODPING_I_KNOW_WHAT_IM_DOING` to `true`.\n\nThis is a temporary measure to limit potential misconfiguration until we fully bundle the `podping.cloud` HTTP front end. Then again, if you're running this, you're probably Dave.\n\n\n### CLI Install\n\nThe following have been tested on Linux and macOS. However, Windows should work also. If you have issues on Windows we highly recommend the [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/) and/or Docker.\n\n#### Using [pipx](https://pypa.github.io/pipx/) (preferred over pip)\n```shell\npipx install podping-hivewriter\n```\n\n#### Using pip\n```shell\npip install --user podping-hivewriter\n```\n\n#### Installing the server\n\nIf you'd like to install the server component, it's hidden behind the extra flag `server`. This is to make it easier to install only the `write` CLI component `podping-hivewriter` on non-standard systems without a configured development enviornment.\n\n```shell\npipx install podping-hivewriter[server]\n```\n\nMake sure you have `~/.local/bin/` on your `PATH`.\n\nSee the dedicated [CLI docs](CLI.md) for more information.\n\n## Podping reasons\n\nPodping accepts various different \"reasons\" for publishing updates to RSS feeds:\n\n* `update` -- A general indication that an RSS feed has been updated\n* `live` -- An indication that an RSS feed has been updated and a contained [``](https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#live-item) tag's status attribute has been changed to live.\n* `liveEnd` -- An indication that an RSS feed has been updated and either the status attribute of an existing [``](https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#live-item) has been changed from live to ended or a [``](https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#live-item) that previously had a status attribute of live has been removed from the feed entirely.\n\nThe canonical list of reasons within the scope of this project is [maintained in this schema](https://github.com/Podcastindex-org/podping-hivewriter/blob/main/src/podping_hivewriter/schema/reason.capnp).\n\n## Mediums\n\nPodping accepts various different \"mediums\" for identifying types of RSS feeds using the Podcast Namespace. Please check the [``](https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#medium) specification for the full list.\n\n`podping-hivewriter` *may* lag behind the specification, and if it does, please let us know or submit a pull request.\n\nThe canonical list of mediums within the scope of this project is [maintained in this schema](https://github.com/Podcastindex-org/podping-hivewriter/blob/main/src/podping_hivewriter/schema/medium.capnp).\n\n## Development\n\nYou'll need a few extras:\n\n1. [capnproto](https://capnproto.org/). Linux: `capnproto` package in your package manager. On a Mac: `brew instal capnp`\n2. [Poetry](https://python-poetry.org/docs/)\n\n\nWe use [poetry](https://python-poetry.org/) for dependency management. Once you have it, clone this repo and run:\n\n```shell\npoetry install\n```\n\nThen to switch to the virtual environment, use:\n\n```shell\npoetry shell\n```\nMake sure you have a the environment variables `PODPING_HIVE_ACCOUNT` and `PODPING_HIVE_POSTING_KEY` set.\n\nAfter that you should be able to run the `podping` command or run the tests:\n\n```shell\npytest\n```\n\nTo run all tests, make sure to set the necessary environment variables for your Hive account. This will take many minutes:\n\n```shell\npytest --runslow\n```\n\n### Building the image locally with Docker\n\nLocally build the podping-hivewriter container with a \"develop\" tag\n\n```shell\ndocker build -t podping-hivewriter:develop .\n```\n\nSee above for more details on running the docker CLI.\n\n## Hive account\n\nIf you need a Hive account, please download the [Hive Keychain extension for your browser](https://hive-keychain.com/) then use this link to get your account from [https://HiveOnboard.com?ref=podping](https://hiveonboard.com?ref=podping). You will need at least 20 Hive Power \"powered up\" to get started (worth around $10). Please contact [@brianoflondon](https://peakd.com/@brianoflondon) brian@podping.org if you need assistance getting set up.\n\nIf you use the [Hiveonboard]((https://hiveonboard.com?ref=podping)) link `podping` will **delegate** enough Hive Power to get you started. If, for any reason, Hiveonboard is not giving out free accounts, please contact [@brianoflondon](https://peakd.com/@brianoflondon) either on [PodcastIndex Social](https://podcastindex.social/invite/U2m6FY3T) or [Telegram](https://t.me/brianoflondon).\n\n### Permissions and Authorization\n\nYou don't need permission, but you do need to tell `podping` that you want to send valid `podpings`:\n\n- Hive is a so-called \"permissionless\" blockchain. Once you have a Hive Account and a minimal amount of Hive Power, that account can post to Hive, including sending `podpings`.\n- Nobody can block any valid Hive Account from sending and nobody can help you if you lose your keys.\n- Whilst anyone can post `podpings` to Hive, there is a need to register your Hive Accountname for those `podpings` to be recognized by all clients. This is merely a spam-prevention measure and clients may choose to ignore it.\n- Please contact new@podping.org or send a Hive Transfer to [@podping](https://peakd.com/@podping) to have your account validated.\n- Side note on keys: `podping` uses the `posting-key` which is the lowest value of the four Hive keys (`owner`, `active`, `memo`, `posting` and there is usually a `master password` which can generate all the keys). That is not to say that losing control of it is a good idea, but that key is not authorized to make financially important transfers. It can, however, post public information so should be treated carefully and kept secure.\n\nFor a [comprehensive explanation of Hive and Podping, please see this post](https://peakd.com/podping/@brianoflondon/podping-and-podcasting-20-funding-to-put-hive-at-the-center-of-global-podcasting-infrastructure).", "author": "Alecks Gates", diff --git a/src/podping_hivewriter/cli/podping.py b/src/podping_hivewriter/cli/podping.py index 4ecda19..4aa1319 100644 --- a/src/podping_hivewriter/cli/podping.py +++ b/src/podping_hivewriter/cli/podping.py @@ -6,14 +6,13 @@ import rfc3987 import typer from lighthive.broadcast.base58 import Base58 -from lighthive.broadcast.key_objects import PrivateKey from podping_hivewriter import __version__ from podping_hivewriter.constants import ( LIVETEST_OPERATION_ID, PODPING_OPERATION_ID, - STARTUP_FAILED_INVALID_ACCOUNT, - STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE, + EXIT_CODE_INVALID_ACCOUNT, + EXIT_CODE_INVALID_POSTING_KEY, ) from podping_hivewriter.hive import get_client from podping_hivewriter.models.medium import Medium, mediums, str_medium_map @@ -78,8 +77,12 @@ class Config: dry_run: bool status: bool ignore_config_updates: bool + hive_operation_period: bool i_know_what_im_doing: bool debug: bool + testnet: bool + testnet_node: str + testnet_chainid: str operation_id: str @@ -129,7 +132,10 @@ def write( 2021-08-30T00:16:01-0500 | INFO | Transaction sent: 00eae43df4a202d94ef6cb797c05f39fbb50631b - JSON size: 97 ``` """ - settings_manager = PodpingSettingsManager(Config.ignore_config_updates) + settings_manager = PodpingSettingsManager( + ignore_updates=Config.ignore_config_updates, + hive_operation_period=Config.hive_operation_period, + ) with PodpingHivewriter( Config.hive_account, @@ -222,7 +228,10 @@ def server( # ZMQ doesn't like the localhost string, force it to ipv4 listen_ip = "127.0.0.1" - settings_manager = PodpingSettingsManager(Config.ignore_config_updates) + settings_manager = PodpingSettingsManager( + ignore_updates=Config.ignore_config_updates, + hive_operation_period=Config.hive_operation_period, + ) _podping_hivewriter = PodpingHivewriter( Config.hive_account, @@ -309,6 +318,14 @@ def callback( help="Periodically prints a status message. " "Runs every diagnostic_report_period defined in podping_settings", ), + hive_operation_period: Optional[int] = typer.Option( + 3, + envvar="PODPING_HIVE_OPERATION_PERIOD", + help="By default the Hivewriter will wait a few seconds gathering IRIs " + "before sending the next batch. This balances resource usage against " + "speed. If this is set here, the setting will override any settings " + "sent by a config update.", + ), ignore_config_updates: Optional[bool] = typer.Option( False, envvar="PODPING_IGNORE_CONFIG_UPDATES", @@ -340,6 +357,7 @@ def callback( Config.dry_run = dry_run Config.status = status Config.ignore_config_updates = ignore_config_updates + Config.hive_operation_period = hive_operation_period Config.i_know_what_im_doing = i_know_what_im_doing Config.debug = debug @@ -364,7 +382,7 @@ def callback( f"check ENV vars and try again" ) logging.error("Exiting") - sys.exit(STARTUP_FAILED_INVALID_ACCOUNT) + sys.exit(EXIT_CODE_INVALID_ACCOUNT) if not is_base58(hive_posting_key): logging.error("Startup of Podping status: FAILED!") @@ -372,7 +390,7 @@ def callback( "Posting Key not valid Base58 - check ENV vars and try again", ) logging.error("Exiting") - sys.exit(STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE) + sys.exit(EXIT_CODE_INVALID_POSTING_KEY) if __name__ == "__main__": diff --git a/src/podping_hivewriter/constants.py b/src/podping_hivewriter/constants.py index d63429a..bc1f31a 100644 --- a/src/podping_hivewriter/constants.py +++ b/src/podping_hivewriter/constants.py @@ -2,10 +2,13 @@ PODPING_OPERATION_ID = "pp" STARTUP_OPERATION_ID = "_startup" -STARTUP_FAILED_UNKNOWN_EXIT_CODE = 10 -STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE = 20 -STARTUP_FAILED_HIVE_API_ERROR_EXIT_CODE = 30 -STARTUP_FAILED_INVALID_ACCOUNT = 40 +EXIT_CODE_UNKNOWN = 10 +EXIT_CODE_INVALID_POSTING_KEY = 20 +EXIT_CODE_HIVE_API_ERROR = 30 +EXIT_CODE_INVALID_ACCOUNT = 40 +EXIT_CODE_STARTUP_ERROR = 50 +EXIT_CODE_STARTUP_RC_EXHAUSTED = 60 +EXIT_CODE_STARTUP_TOO_MANY_POSTS = 60 PODPING_SETTINGS_KEY = "podping-settings" # Operation JSON must be less than or equal to 8192 bytes. diff --git a/src/podping_hivewriter/exceptions.py b/src/podping_hivewriter/exceptions.py index 841bdfd..a70ab4b 100644 --- a/src/podping_hivewriter/exceptions.py +++ b/src/podping_hivewriter/exceptions.py @@ -4,3 +4,7 @@ class PodpingCustomJsonPayloadExceeded(RuntimeError): class TooManyCustomJsonsPerBlock(RuntimeError): """Raise when trying to write more than 5 custom_jsons in a single block""" + + +class NotEnoughResourceCredits(RuntimeError): + """Raise when we run out of Resource Credits""" diff --git a/src/podping_hivewriter/hive.py b/src/podping_hivewriter/hive.py index d95dd00..086f0a7 100644 --- a/src/podping_hivewriter/hive.py +++ b/src/podping_hivewriter/hive.py @@ -1,9 +1,13 @@ import asyncio +import itertools import logging +import os from timeit import default_timer as timer from typing import List, Optional, Set +import backoff from lighthive.client import Client +from lighthive.exceptions import RPCNodeException from podping_hivewriter.async_wrapper import sync_to_async @@ -19,6 +23,21 @@ def get_client( api_type="condenser_api", ) -> Client: try: + if os.getenv("PODPING_TESTNET", "False").lower() in ( + "true", + "1", + "t", + ): + nodes = [os.getenv("PODPING_TESTNET_NODE")] + chain = {"chain_id": os.getenv("PODPING_TESTNET_CHAINID")} + else: + nodes = [ + "https://api.hive.blog", + "https://api.deathwing.me", + "https://hive-api.arcange.eu", + "https://api.openhive.network", + "https://api.hive.blue", + ] client = Client( keys=posting_keys, nodes=nodes, @@ -27,6 +46,10 @@ def get_client( loglevel=loglevel, chain=chain, automatic_node_selection=automatic_node_selection, + backoff_mode=backoff.fibo, + backoff_max_tries=3, + load_balance_nodes=True, + circuit_breaker=True, ) return client(api_type) except Exception as ex: @@ -42,8 +65,12 @@ def get_allowed_accounts( if not client: client = get_client() - master_account = client.account(account_name) - return set(master_account.following()) + for _ in itertools.repeat(None): + try: + master_account = client.account(account_name) + return set(master_account.following()) + except Exception as e: + logging.warning(f"Unable to get account followers: {e} - retrying") async def listen_for_custom_json_operations( @@ -61,30 +88,40 @@ async def listen_for_custom_json_operations( ) while True: start_time = timer() - head_block = (await async_get_dynamic_global_properties())["head_block_number"] - while (head_block - current_block) > 0: - block = await async_get_block({"block_num": current_block}) - for op in ( - (trx_id, op) - for trx_id, transaction in enumerate(block["block"]["transactions"]) - for op in transaction["operations"] - ): - if op[1]["type"] == "custom_json_operation": - yield { - "block": current_block, - "timestamp": block["block"]["timestamp"], - "trx_id": op[0], - "op": [ - "custom_json", - op[1]["value"], - ], - } - current_block += 1 + try: head_block = (await async_get_dynamic_global_properties())[ "head_block_number" ] + while (head_block - current_block) > 0: + try: + block = await async_get_block({"block_num": current_block}) + for op in ( + (trx_id, op) + for trx_id, transaction in enumerate( + block["block"]["transactions"] + ) + for op in transaction["operations"] + ): + if op[1]["type"] == "custom_json_operation": + yield { + "block": current_block, + "timestamp": block["block"]["timestamp"], + "trx_id": op[0], + "op": [ + "custom_json", + op[1]["value"], + ], + } + current_block += 1 + head_block = (await async_get_dynamic_global_properties())[ + "head_block_number" + ] + except RPCNodeException as e: + logging.warning(f"Hive API error {e}") - end_time = timer() - sleep_time = 3 - (end_time - start_time) - if sleep_time > 0 and (head_block - current_block) <= 0: - await asyncio.sleep(sleep_time) + end_time = timer() + sleep_time = 3 - (end_time - start_time) + if sleep_time > 0 and (head_block - current_block) <= 0: + await asyncio.sleep(sleep_time) + except RPCNodeException as e: + logging.warning(f"Hive API error {e}") diff --git a/src/podping_hivewriter/models/podping_settings.py b/src/podping_hivewriter/models/podping_settings.py index f72e82c..7303251 100644 --- a/src/podping_hivewriter/models/podping_settings.py +++ b/src/podping_hivewriter/models/podping_settings.py @@ -7,10 +7,10 @@ class PodpingSettings(BaseModel): """Dataclass for settings we will fetch from Hive""" hive_operation_period: int = 3 - max_url_list_bytes: int = 7500 - diagnostic_report_period: int = 60 + max_url_list_bytes: int = 8000 + diagnostic_report_period: int = 180 control_account: str = "podping" - control_account_check_period: int = 60 + control_account_check_period: int = 180 test_nodes: Tuple[str, ...] = ("https://testnet.openhive.network",) @validator("hive_operation_period") diff --git a/src/podping_hivewriter/podping_hivewriter.py b/src/podping_hivewriter/podping_hivewriter.py index 86f5491..9988dae 100644 --- a/src/podping_hivewriter/podping_hivewriter.py +++ b/src/podping_hivewriter/podping_hivewriter.py @@ -6,25 +6,27 @@ import sys import uuid from datetime import datetime, timedelta -from itertools import cycle from timeit import default_timer as timer -from typing import List, Set, Tuple, Union, Optional +from typing import List, Optional, Set, Tuple, Union import rfc3987 from lighthive.datastructures import Operation from lighthive.exceptions import RPCNodeException -from lighthive.node_picker import compare_nodes from podping_hivewriter import __version__ as podping_hivewriter_version from podping_hivewriter.async_context import AsyncContext from podping_hivewriter.async_wrapper import sync_to_async from podping_hivewriter.constants import ( + EXIT_CODE_INVALID_POSTING_KEY, + EXIT_CODE_UNKNOWN, HIVE_CUSTOM_OP_DATA_MAX_LENGTH, - STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE, - STARTUP_FAILED_UNKNOWN_EXIT_CODE, STARTUP_OPERATION_ID, + EXIT_CODE_STARTUP_ERROR, + EXIT_CODE_STARTUP_RC_EXHAUSTED, + EXIT_CODE_STARTUP_TOO_MANY_POSTS, ) from podping_hivewriter.exceptions import ( + NotEnoughResourceCredits, PodpingCustomJsonPayloadExceeded, TooManyCustomJsonsPerBlock, ) @@ -72,7 +74,6 @@ def __init__( self.lighthive_client = get_client( posting_keys=posting_keys, loglevel=logging.ERROR, - automatic_node_selection=False, # TODO: File upstream lighthive bug because it runs asyncio in a new loop ) self._async_hive_broadcast = sync_to_async( @@ -110,12 +111,11 @@ async def _startup(self): ) except Exception as ex: - logging.error(f"Unknown error occurred: {ex}", exc_info=True) + logging.exception("Unknown error occurred in _startup", stack_info=True) raise ex if self.resource_test and not self.dry_run: await self.test_hive_resources() - await self.automatic_node_selection() logging.info(f"Hive account: @{self.server_account}") @@ -128,15 +128,6 @@ async def _startup(self): self._startup_done = True - async def automatic_node_selection(self) -> None: - """Use the automatic async feature to find the fastest API""" - self.lighthive_client._node_list = await compare_nodes( - nodes=self.lighthive_client.nodes, logger=self.lighthive_client.logger - ) - self.lighthive_client.node_list = cycle(self.lighthive_client._node_list) - self.lighthive_client.next_node() - logging.info(f"Lighthive Fastest: {self.lighthive_client.current_node}") - async def test_hive_resources(self): logging.info( "Podping startup sequence initiated, please stand by, " @@ -144,16 +135,8 @@ async def test_hive_resources(self): ) # noinspection PyBroadException - try: # Now post two custom json to test. - account = self.lighthive_client.account(self.server_account) - manabar = account.get_resource_credit_info() - - logging.info( - f"Testing Account Resource Credits" - f' - before {manabar.get("last_mana_percent"):.2f}%' - ) - rc = self.lighthive_client.rc() - + try: + # post custom json to test. custom_json = { "server_account": self.server_account, "message": "Podping startup initiated", @@ -163,48 +146,68 @@ async def test_hive_resources(self): startup_hive_operation_id = self.operation_id + STARTUP_OPERATION_ID - op, size_of_json = await self.construct_operation( - custom_json, startup_hive_operation_id - ) - rc_cost = rc.get_cost(op) - percent_after = ( - 100 - * (manabar.get("last_mana") - (1e6 * rc_cost * 100)) - / manabar["max_mana"] - ) - percent_drop = manabar.get("last_mana_percent") - percent_after - capacity = (100 / percent_drop) * 100 - logging.info( - f"Calculating Account Resource Credits " - f"for 100 pings: {percent_drop:.2f}% | " - f"Capacity: {capacity:,.0f}" - ) + self.construct_operation(custom_json, startup_hive_operation_id) custom_json["v"] = podping_hivewriter_version - custom_json["capacity"] = f"{capacity:,.0f}" custom_json["message"] = "Podping startup complete" custom_json["hive"] = str(self.lighthive_client.current_node) - await self.send_notification(custom_json, startup_hive_operation_id) + startup_notification_attempts_max = len(self.lighthive_client.node_list) + # Retry startup notification for every node before giving up + for i in range(startup_notification_attempts_max): + try: + await self.send_notification(custom_json, startup_hive_operation_id) + break + except RPCNodeException: + if i == startup_notification_attempts_max - 1: + raise logging.info("Startup of Podping status: SUCCESS! Hit the BOOST Button.") except ValueError as ex: if str(ex) == "Error loading Base58 object": - logging.error( - f"Startup of Podping status: FAILED! {ex}", - exc_info=True, + logging.exception( + "Startup of Podping status: FAILED! Invalid posting key", + stack_info=True, ) logging.error("Exiting") - sys.exit(STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE) - - except Exception as ex: - logging.error( - f"Startup of Podping status: FAILED! {ex}", - exc_info=True, + sys.exit(EXIT_CODE_INVALID_POSTING_KEY) + else: + logging.exception( + "Startup of Podping status: FAILED! Unknown error", stack_info=True + ) + logging.error("Exiting") + sys.exit(EXIT_CODE_UNKNOWN) + except NotEnoughResourceCredits: + logging.exception( + "Startup of Podping status: FAILED! " + "Not enough resource credits to post", + stack_info=True, + ) + logging.error("Exiting") + sys.exit(EXIT_CODE_STARTUP_RC_EXHAUSTED) + except TooManyCustomJsonsPerBlock: + logging.exception( + "Startup of Podping status: FAILED! " + "The given Hive account is is posting too quickly", + stack_info=True, + ) + logging.error("Exiting") + sys.exit(EXIT_CODE_STARTUP_TOO_MANY_POSTS) + except RPCNodeException: + logging.exception( + "Startup of Podping status: FAILED! " + "Unable to send startup notification", + stack_info=True, + ) + logging.error("Exiting") + sys.exit(EXIT_CODE_STARTUP_ERROR) + except Exception: + logging.exception( + "Startup of Podping status: FAILED! Unknown error", stack_info=True ) logging.error("Exiting") - sys.exit(STARTUP_FAILED_UNKNOWN_EXIT_CODE) + sys.exit(EXIT_CODE_UNKNOWN) async def wait_startup(self): settings = await self.settings_manager.get_settings() @@ -217,10 +220,10 @@ async def _hive_status_loop(self): await self.output_hive_status() settings = await self.settings_manager.get_settings() await asyncio.sleep(settings.diagnostic_report_period) - except Exception as ex: - logging.error(f"{ex} occurred", exc_info=True) except asyncio.CancelledError: raise + except Exception: + logging.exception("Unknown in _hive_status_loop", stack_info=True) async def _iri_batch_handler_loop(self): """Opens and watches a queue and sends notifications to Hive one by one""" @@ -247,8 +250,8 @@ async def _iri_batch_handler_loop(self): ) except asyncio.CancelledError: raise - except Exception as ex: - logging.error(f"{ex} occurred", exc_info=True) + except Exception: + logging.exception("Unknown in _iri_batch_handler_loop", stack_info=True) raise async def _iri_batch_loop(self): @@ -300,8 +303,11 @@ async def get_from_queue(): pass except asyncio.CancelledError: raise - except Exception as ex: - logging.error(f"{ex} occurred", exc_info=True) + except Exception: + logging.exception( + "Unknown error in _iri_batch_loop", stack_info=True + ) + raise finally: # Always get the time of the loop duration = timer() - start @@ -316,8 +322,9 @@ async def get_from_queue(): ) except asyncio.CancelledError: raise - except Exception as ex: - logging.error(f"{ex} occurred", exc_info=True) + except Exception: + logging.exception("Unknown error in _iri_batch_loop", stack_info=True) + raise async def _zmq_response_loop(self): import zmq.asyncio @@ -343,8 +350,11 @@ async def _zmq_response_loop(self): except asyncio.CancelledError: socket.close() raise - except Exception as ex: - logging.error(f"{ex} occurred", exc_info=True) + except Exception: + logging.exception( + "Unknown error in _zmq_response_loop", stack_info=True + ) + raise async def num_operations_in_queue(self) -> int: async with self._iris_in_flight_lock: @@ -354,7 +364,6 @@ async def output_hive_status(self) -> None: """Output the name of the current hive node on a regular basis""" up_time = timedelta(seconds=int(timer() - self.startup_time)) - await self.automatic_node_selection() last_node = self.lighthive_client.current_node logging.info( f"Status - Uptime: {up_time} | " @@ -364,7 +373,7 @@ async def output_hive_status(self) -> None: f"last_node: {last_node}" ) - async def construct_operation( + def construct_operation( self, payload: dict, hive_operation_id: Union[HiveOperationId, str] ) -> Tuple[Operation, int]: """Builed the operation for the blockchain""" @@ -389,20 +398,15 @@ async def send_notification( ) -> None: """Build and send an operation to the blockchain""" try: - op, size_of_json = await self.construct_operation( - payload, hive_operation_id - ) + op, size_of_json = self.construct_operation(payload, hive_operation_id) # if you want to FORCE the error condition for >5 operations # in one block, uncomment this line. # op = [op] * 6 - # Use asynchronous broadcast but means we don't get back tx, kinder to - # API servers await self._async_hive_broadcast(op=op, dry_run=self.dry_run) logging.info(f"Lighthive Node: {self.lighthive_client.current_node}") logging.info(f"JSON size: {size_of_json}") - except RPCNodeException as ex: logging.error(f"send_notification error: {ex}") try: @@ -410,19 +414,23 @@ async def send_notification( r"plugin exception.*custom json.*", ex.raw_body["error"]["message"], ): - self.lighthive_client.next_node() raise TooManyCustomJsonsPerBlock() + if re.match( + r".*not enough RC mana.*", + ex.raw_body["error"]["message"], + ): + logging.error(ex.raw_body["error"]["message"]) + raise NotEnoughResourceCredits() else: raise ex except (KeyError, AttributeError): + logging.error("Unexpected error format from Hive") raise ex - - except PodpingCustomJsonPayloadExceeded as ex: - raise ex - - except Exception as ex: - logging.error(f"{ex}") - raise ex + except PodpingCustomJsonPayloadExceeded: + raise + except Exception: + logging.exception("Unknown error in send_notification", stack_info=True) + raise async def send_notification_iri( self, @@ -468,16 +476,14 @@ async def failure_retry( for _ in itertools.repeat(None): # Sleep a maximum of 5 minutes, 3 additional seconds for every retry - sleep_time = min(failure_count * 3, 300) if failure_count > 0: - logging.warning(f"Waiting {sleep_time}s before retry") - await asyncio.sleep(sleep_time) logging.info( f"FAILURE COUNT: {failure_count} - RETRYING {len(iri_set)} IRIs" ) else: logging.info(f"Received {len(iri_set)} IRIs") + # noinspection PyBroadException try: await self.send_notification_iris( iris=iri_set, @@ -485,15 +491,13 @@ async def failure_retry( reason=reason or self.reason, ) if failure_count > 0: - logging.info( - f"FAILURE CLEARED after {failure_count} retries, {sleep_time}s" - ) + logging.info(f"FAILURE CLEARED after {failure_count} retries") return failure_count except RPCNodeException as ex: - logging.exception(f"Failed to send {len(iri_set)} IRIs") + logging.error(f"Failed to send {len(iri_set)} IRIs") try: # Test if we have a well-formed Hive error message - logging.exception(ex) + logging.error(ex) if ( ex.raw_body["error"]["data"]["name"] == "tx_missing_posting_auth" @@ -503,28 +507,36 @@ async def failure_retry( logging.debug(iri) logging.error( f"Terminating: exit code: " - f"{STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE}" + f"{EXIT_CODE_INVALID_POSTING_KEY}" ) - sys.exit(STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE) + sys.exit(EXIT_CODE_INVALID_POSTING_KEY) except (KeyError, AttributeError): - logging.warning( - f"Malformed error response from node: {self.lighthive_client.current_node}" - ) - except Exception: - logging.info(f"Current node: {self.lighthive_client.current_node}") - logging.info(self.lighthive_client.nodes) - logging.exception("Unexpected condition in error text from Hive") - sys.exit(STARTUP_FAILED_UNKNOWN_EXIT_CODE) - - except Exception as ex: - logging.exception(ex) - logging.exception(f"Failed to send {len(iri_set)} IRIs") + logging.warning("Malformed error response") + except NotEnoughResourceCredits as ex: + logging.warning(ex) + # 10s + exponential back off: need time for RC delegation + # script to kick in + sleep_for = 10 * 2**failure_count + logging.warning(f"Sleeping for {sleep_for}s") + await asyncio.sleep(sleep_for) + except TooManyCustomJsonsPerBlock as ex: + logging.warning(ex) + # Wait for the next block to retry + sleep_for = ( + await self.settings_manager.get_settings() + ).hive_operation_period + logging.warning(f"Sleeping for {sleep_for}s") + await asyncio.sleep(sleep_for) + except Exception: + logging.info(f"Current node: {self.lighthive_client.current_node}") + logging.info(self.lighthive_client.nodes) + logging.exception("Unknown error in failure_retry", stack_info=True) + logging.error(f"Failed to send {len(iri_set)} IRIs") if logging.DEBUG >= logging.root.level: for iri in iri_set: logging.debug(iri) - + sys.exit(EXIT_CODE_UNKNOWN) finally: - self.lighthive_client.next_node() failure_count += 1 return failure_count diff --git a/src/podping_hivewriter/podping_settings_manager.py b/src/podping_hivewriter/podping_settings_manager.py index 588518d..c05f178 100644 --- a/src/podping_hivewriter/podping_settings_manager.py +++ b/src/podping_hivewriter/podping_settings_manager.py @@ -2,18 +2,22 @@ import logging from timeit import default_timer as timer +from pydantic import ValidationError + from podping_hivewriter.async_context import AsyncContext from podping_hivewriter.models.podping_settings import PodpingSettings from podping_hivewriter.podping_settings import get_podping_settings -from pydantic import ValidationError class PodpingSettingsManager(AsyncContext): - def __init__(self, ignore_updates=False): + def __init__(self, ignore_updates=False, hive_operation_period=None): super().__init__() self.ignore_updates = ignore_updates - + if hive_operation_period: + self.override_hive_operation_period = hive_operation_period + else: + self.override_hive_operation_period = False self.last_update_time = float("-inf") self._settings = PodpingSettings() @@ -53,6 +57,10 @@ async def update_podping_settings(self) -> None: ) async with self._settings_lock: self._settings = podping_settings + if self.override_hive_operation_period: + self._settings.hive_operation_period = ( + self.override_hive_operation_period + ) async def get_settings(self) -> PodpingSettings: async with self._settings_lock: diff --git a/tests/integration/test_get_allowed_accounts.py b/tests/integration/test_get_allowed_accounts.py index f4d9365..db9aebc 100644 --- a/tests/integration/test_get_allowed_accounts.py +++ b/tests/integration/test_get_allowed_accounts.py @@ -1,14 +1,13 @@ import logging -import pytest -from podping_hivewriter.hive import get_allowed_accounts +import pytest -from lighthive.client import Client +from podping_hivewriter.hive import get_allowed_accounts, get_client @pytest.mark.asyncio async def test_get_allowed_accounts(): # Checks the allowed accounts checkup - client = Client(loglevel=logging.WARN) + client = get_client(loglevel=logging.WARN) allowed_accounts = get_allowed_accounts(client) assert type(allowed_accounts) == set and len(allowed_accounts) > 0 diff --git a/tests/integration/test_startup_checks_and_write_cli_single.py b/tests/integration/test_startup_checks_and_write_cli_single.py index de602c1..1b9f7ca 100644 --- a/tests/integration/test_startup_checks_and_write_cli_single.py +++ b/tests/integration/test_startup_checks_and_write_cli_single.py @@ -3,20 +3,18 @@ from platform import python_version as pv import pytest -from lighthive.client import Client from typer.testing import CliRunner from podping_hivewriter.cli.podping import app from podping_hivewriter.constants import ( LIVETEST_OPERATION_ID, - STARTUP_FAILED_INVALID_ACCOUNT, - STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE, + EXIT_CODE_INVALID_ACCOUNT, + EXIT_CODE_INVALID_POSTING_KEY, ) -from podping_hivewriter.hive import listen_for_custom_json_operations +from podping_hivewriter.hive import get_client, listen_for_custom_json_operations from podping_hivewriter.models.hive_operation_id import HiveOperationId from podping_hivewriter.models.medium import Medium from podping_hivewriter.models.reason import Reason -from podping_hivewriter.podping_settings_manager import PodpingSettingsManager @pytest.mark.asyncio @@ -25,9 +23,7 @@ async def test_startup_checks_and_write_cli_single(): runner = CliRunner() - settings_manager = PodpingSettingsManager(ignore_updates=True) - - client = Client() + client = get_client() session_uuid = uuid.uuid4() session_uuid_str = str(session_uuid) @@ -63,7 +59,6 @@ async def get_iri_from_blockchain(start_block: int): iri_found = True break - del settings_manager assert iri_found @@ -82,9 +77,9 @@ async def test_startup_failures(): args = ["--livetest", "--hive-account", "_podping", "write", iri] result = runner.invoke(app, args) - assert result.exit_code == STARTUP_FAILED_INVALID_ACCOUNT + assert result.exit_code == EXIT_CODE_INVALID_ACCOUNT args = ["--livetest", "--hive-posting-key", "not_a_valid_key", "write", iri] result = runner.invoke(app, args) - assert result.exit_code == STARTUP_FAILED_INVALID_POSTING_KEY_EXIT_CODE + assert result.exit_code == EXIT_CODE_INVALID_POSTING_KEY diff --git a/tests/integration/test_write_cli_multiple.py b/tests/integration/test_write_cli_multiple.py index afa34e5..4d7d5ed 100644 --- a/tests/integration/test_write_cli_multiple.py +++ b/tests/integration/test_write_cli_multiple.py @@ -1,19 +1,18 @@ import json import random import uuid -from random import randint from platform import python_version as pv +from random import randint import pytest -from lighthive.client import Client from typer.testing import CliRunner from podping_hivewriter.cli.podping import app from podping_hivewriter.constants import LIVETEST_OPERATION_ID -from podping_hivewriter.hive import listen_for_custom_json_operations +from podping_hivewriter.hive import get_client, listen_for_custom_json_operations from podping_hivewriter.models.hive_operation_id import HiveOperationId -from podping_hivewriter.models.medium import str_medium_map, mediums -from podping_hivewriter.models.reason import str_reason_map, reasons +from podping_hivewriter.models.medium import mediums, str_medium_map +from podping_hivewriter.models.reason import reasons, str_reason_map @pytest.mark.asyncio @@ -22,7 +21,7 @@ async def test_write_cli_multiple(): runner = CliRunner() - client = Client() + client = get_client() session_uuid = uuid.uuid4() session_uuid_str = str(session_uuid) diff --git a/tests/integration/test_write_cli_single.py b/tests/integration/test_write_cli_single.py index 4aa5c84..7b34bcf 100644 --- a/tests/integration/test_write_cli_single.py +++ b/tests/integration/test_write_cli_single.py @@ -4,15 +4,14 @@ from platform import python_version as pv import pytest -from lighthive.client import Client from typer.testing import CliRunner from podping_hivewriter.cli.podping import app from podping_hivewriter.constants import LIVETEST_OPERATION_ID -from podping_hivewriter.hive import listen_for_custom_json_operations +from podping_hivewriter.hive import get_client, listen_for_custom_json_operations from podping_hivewriter.models.hive_operation_id import HiveOperationId -from podping_hivewriter.models.medium import str_medium_map, mediums -from podping_hivewriter.models.reason import str_reason_map, reasons +from podping_hivewriter.models.medium import mediums, str_medium_map +from podping_hivewriter.models.reason import reasons, str_reason_map @pytest.mark.asyncio @@ -20,7 +19,7 @@ @pytest.mark.slow async def test_write_cli_single(): runner = CliRunner() - client = Client() + client = get_client() session_uuid = uuid.uuid4() session_uuid_str = str(session_uuid) diff --git a/tests/integration/test_write_cli_single_simulcast.py b/tests/integration/test_write_cli_single_simulcast.py index 3c5b35f..02806ea 100644 --- a/tests/integration/test_write_cli_single_simulcast.py +++ b/tests/integration/test_write_cli_single_simulcast.py @@ -1,18 +1,17 @@ import asyncio import json import random -from timeit import default_timer as timer import uuid from platform import python_version as pv +from timeit import default_timer as timer import pytest -from lighthive.client import Client from typer.testing import CliRunner from podping_hivewriter.cli.podping import app -from podping_hivewriter.hive import listen_for_custom_json_operations -from podping_hivewriter.models.medium import str_medium_map, mediums -from podping_hivewriter.models.reason import str_reason_map, reasons +from podping_hivewriter.hive import get_client, listen_for_custom_json_operations +from podping_hivewriter.models.medium import mediums, str_medium_map +from podping_hivewriter.models.reason import reasons, str_reason_map @pytest.mark.asyncio @@ -24,7 +23,7 @@ async def test_write_cli_single_simulcast(): runner = CliRunner() start = timer() - client = Client() + client = get_client() session_uuid = uuid.uuid4() session_uuid_str = str(session_uuid) diff --git a/tests/integration/test_write_zmq_multiple.py b/tests/integration/test_write_zmq_multiple.py index 8e3880b..a3c079a 100644 --- a/tests/integration/test_write_zmq_multiple.py +++ b/tests/integration/test_write_zmq_multiple.py @@ -3,16 +3,15 @@ import os import random import uuid -from random import randint from platform import python_version as pv +from random import randint import pytest import zmq import zmq.asyncio -from lighthive.client import Client from podping_hivewriter.constants import LIVETEST_OPERATION_ID -from podping_hivewriter.hive import listen_for_custom_json_operations +from podping_hivewriter.hive import get_client, listen_for_custom_json_operations from podping_hivewriter.models.hive_operation_id import HiveOperationId from podping_hivewriter.models.medium import mediums, str_medium_map from podping_hivewriter.models.reason import reasons, str_reason_map @@ -26,7 +25,7 @@ async def test_write_zmq_multiple(event_loop): settings_manager = PodpingSettingsManager(ignore_updates=True) - client = Client() + client = get_client() session_uuid = uuid.uuid4() session_uuid_str = str(session_uuid) diff --git a/tests/integration/test_write_zmq_single.py b/tests/integration/test_write_zmq_single.py index 38b0e08..56d6c7b 100644 --- a/tests/integration/test_write_zmq_single.py +++ b/tests/integration/test_write_zmq_single.py @@ -7,13 +7,12 @@ import pytest import zmq import zmq.asyncio -from lighthive.client import Client from podping_hivewriter.constants import LIVETEST_OPERATION_ID -from podping_hivewriter.hive import listen_for_custom_json_operations +from podping_hivewriter.hive import get_client, listen_for_custom_json_operations from podping_hivewriter.models.hive_operation_id import HiveOperationId -from podping_hivewriter.models.medium import str_medium_map, mediums -from podping_hivewriter.models.reason import str_reason_map, reasons +from podping_hivewriter.models.medium import mediums, str_medium_map +from podping_hivewriter.models.reason import reasons, str_reason_map from podping_hivewriter.podping_hivewriter import PodpingHivewriter from podping_hivewriter.podping_settings_manager import PodpingSettingsManager @@ -24,7 +23,7 @@ async def test_write_zmq_single(event_loop): settings_manager = PodpingSettingsManager(ignore_updates=True) - client = Client() + client = get_client() session_uuid = uuid.uuid4() session_uuid_str = str(session_uuid) diff --git a/tests/regression/test_#48_send_notification_raises_rpcexception.py b/tests/regression/test_#48_send_notification_raises_rpcexception.py index 68fb5cb..ecbf1a0 100644 --- a/tests/regression/test_#48_send_notification_raises_rpcexception.py +++ b/tests/regression/test_#48_send_notification_raises_rpcexception.py @@ -5,14 +5,16 @@ import lighthive import pytest - from lighthive.client import Client from lighthive.exceptions import RPCNodeException from podping_hivewriter.constants import LIVETEST_OPERATION_ID -from podping_hivewriter.exceptions import TooManyCustomJsonsPerBlock -from podping_hivewriter.models.medium import str_medium_map, mediums -from podping_hivewriter.models.reason import str_reason_map, reasons +from podping_hivewriter.exceptions import ( + NotEnoughResourceCredits, + TooManyCustomJsonsPerBlock, +) +from podping_hivewriter.models.medium import mediums, str_medium_map +from podping_hivewriter.models.reason import reasons, str_reason_map from podping_hivewriter.podping_hivewriter import PodpingHivewriter from podping_hivewriter.podping_settings_manager import PodpingSettingsManager @@ -55,6 +57,9 @@ def mock_broadcast(*args, **kwargs): with pytest.raises(RPCNodeException): await podping_hivewriter.send_notification_iri(iri, medium, reason) + with pytest.raises(RPCNodeException): + await podping_hivewriter.send_notification_iris({iri}, medium, reason) + podping_hivewriter.close() @@ -98,6 +103,9 @@ def mock_broadcast(*args, **kwargs): with pytest.raises(RPCNodeException): await podping_hivewriter.send_notification_iri(iri, medium, reason) + with pytest.raises(RPCNodeException): + await podping_hivewriter.send_notification_iris({iri}, medium, reason) + podping_hivewriter.close() @@ -141,4 +149,53 @@ def mock_broadcast(*args, **kwargs): with pytest.raises(TooManyCustomJsonsPerBlock): await podping_hivewriter.send_notification_iri(iri, medium, reason) + with pytest.raises(TooManyCustomJsonsPerBlock): + await podping_hivewriter.send_notification_iris({iri}, medium, reason) + + podping_hivewriter.close() + + +@pytest.mark.asyncio +async def test_send_notification_raises_not_enough_resource_credits( + event_loop, monkeypatch +): + settings_manager = PodpingSettingsManager(ignore_updates=True) + + def mock_broadcast(*args, **kwargs): + raise RPCNodeException( + "mock_broadcast exception", + code=42, + raw_body={"error": {"message": "payer has not enough RC mana bizz"}}, + ) + + monkeypatch.setattr(lighthive.client.Client, "broadcast", mock_broadcast) + + session_uuid = uuid.uuid4() + session_uuid_str = str(session_uuid) + + test_name = "test_send_notification_raises_not_enough_resource_credits" + iri = f"https://example.com?t={test_name}&v={pv()}&s={session_uuid_str}" + + medium = str_medium_map[random.sample(sorted(mediums), 1)[0]] + reason = str_reason_map[random.sample(sorted(reasons), 1)[0]] + + podping_hivewriter = PodpingHivewriter( + os.environ["PODPING_HIVE_ACCOUNT"], + [os.environ["PODPING_HIVE_POSTING_KEY"]], + settings_manager, + medium=medium, + reason=reason, + daemon=False, + resource_test=False, + operation_id=LIVETEST_OPERATION_ID, + ) + + await podping_hivewriter.wait_startup() + + with pytest.raises(NotEnoughResourceCredits): + await podping_hivewriter.send_notification_iri(iri, medium, reason) + + with pytest.raises(NotEnoughResourceCredits): + await podping_hivewriter.send_notification_iris({iri}, medium, reason) + podping_hivewriter.close() diff --git a/tests/regression/test_#51_failure_retry_handles_invalid_error_response.py b/tests/regression/test_#51_failure_retry_handles_invalid_error_response.py index 600166e..902cd39 100644 --- a/tests/regression/test_#51_failure_retry_handles_invalid_error_response.py +++ b/tests/regression/test_#51_failure_retry_handles_invalid_error_response.py @@ -5,14 +5,13 @@ import lighthive import pytest - -from lighthive.client import Client from lighthive.exceptions import RPCNodeException from podping_hivewriter import podping_hivewriter from podping_hivewriter.constants import LIVETEST_OPERATION_ID -from podping_hivewriter.models.medium import str_medium_map, mediums -from podping_hivewriter.models.reason import str_reason_map, reasons +from podping_hivewriter.exceptions import NotEnoughResourceCredits +from podping_hivewriter.models.medium import mediums, str_medium_map +from podping_hivewriter.models.reason import reasons, str_reason_map from podping_hivewriter.podping_hivewriter import PodpingHivewriter from podping_hivewriter.podping_settings_manager import PodpingSettingsManager @@ -24,18 +23,16 @@ async def test_failure_retry_handles_invalid_error_response( settings_manager = PodpingSettingsManager(ignore_updates=True) logging_warning_stub = mocker.stub(name="logging_warning_stub") - logging_exception_stub = mocker.stub(name="logging_exception_stub") + logging_error_stub = mocker.stub(name="logging_error_stub") def mock_broadcast(*args, **kwargs): raise RPCNodeException( "mock_broadcast exception", code=42, raw_body={"foo": "bar"} ) - mocker.patch.object(podping_hivewriter.itertools, "repeat", return_value=range(1)) monkeypatch.setattr(podping_hivewriter.logging, "warning", logging_warning_stub) - monkeypatch.setattr(podping_hivewriter.logging, "exception", logging_exception_stub) + monkeypatch.setattr(podping_hivewriter.logging, "error", logging_error_stub) monkeypatch.setattr(lighthive.client.Client, "broadcast", mock_broadcast) - lighthive_client_next_node_spy = mocker.spy(lighthive.client.Client, "next_node") session_uuid = uuid.uuid4() session_uuid_str = str(session_uuid) @@ -59,13 +56,64 @@ def mock_broadcast(*args, **kwargs): await writer.wait_startup() - lighthive_client_next_node_spy.reset_mock() + mocker.patch.object(podping_hivewriter.itertools, "repeat", return_value=range(1)) + logging_warning_stub.reset_mock() + + failure_count = await writer.failure_retry({iri}, medium, reason) + + writer.close() + + logging_warning_stub.assert_called_once_with("Malformed error response") + assert logging_error_stub.call_count == 4 + assert failure_count == 1 + + +@pytest.mark.asyncio +async def test_failure_retry_handles_not_enough_resource_credits( + event_loop, mocker, monkeypatch +): + settings_manager = PodpingSettingsManager(ignore_updates=True) + + logging_warning_stub = mocker.stub(name="logging_warning_stub") + logging_error_stub = mocker.stub(name="logging_error_stub") + + def mock_broadcast(*args, **kwargs): + raise NotEnoughResourceCredits("testing") + + monkeypatch.setattr(podping_hivewriter.logging, "warning", logging_warning_stub) + monkeypatch.setattr(podping_hivewriter.logging, "error", logging_error_stub) + monkeypatch.setattr(lighthive.client.Client, "broadcast", mock_broadcast) + + session_uuid = uuid.uuid4() + session_uuid_str = str(session_uuid) + + test_name = "failure_retry_handles_not_enough_resource_credits" + iri = f"https://example.com?t={test_name}&v={pv()}&s={session_uuid_str}" + + medium = str_medium_map[random.sample(sorted(mediums), 1)[0]] + reason = str_reason_map[random.sample(sorted(reasons), 1)[0]] + + writer = PodpingHivewriter( + os.environ["PODPING_HIVE_ACCOUNT"], + [os.environ["PODPING_HIVE_POSTING_KEY"]], + settings_manager, + medium=medium, + reason=reason, + daemon=False, + resource_test=False, + operation_id=LIVETEST_OPERATION_ID, + ) + + await writer.wait_startup() + + mocker.patch.object(podping_hivewriter.itertools, "repeat", return_value=range(1)) + logging_warning_stub.reset_mock() failure_count = await writer.failure_retry({iri}, medium, reason) writer.close() - logging_warning_stub.assert_called_once() - lighthive_client_next_node_spy.assert_called_once() - assert logging_exception_stub.call_count == 2 + logging_warning_stub.assert_called_with("Sleeping for 10s") + assert logging_warning_stub.call_count == 2 + assert logging_error_stub.call_count == 1 assert failure_count == 1 diff --git a/tests/regression/test_#54_override_hive_operation_period_command_line.py b/tests/regression/test_#54_override_hive_operation_period_command_line.py new file mode 100644 index 0000000..ab0f225 --- /dev/null +++ b/tests/regression/test_#54_override_hive_operation_period_command_line.py @@ -0,0 +1,58 @@ +import json +import uuid +from platform import python_version as pv + +import pytest +from typer.testing import CliRunner + +from podping_hivewriter.cli.podping import app +from podping_hivewriter.constants import LIVETEST_OPERATION_ID +from podping_hivewriter.hive import get_client, listen_for_custom_json_operations +from podping_hivewriter.models.hive_operation_id import HiveOperationId +from podping_hivewriter.models.medium import Medium +from podping_hivewriter.models.reason import Reason + + +@pytest.mark.asyncio +@pytest.mark.timeout(600) +@pytest.mark.slow +async def test_startup_checks_and_write_cli_single(): + runner = CliRunner() + + client = get_client() + + session_uuid = uuid.uuid4() + session_uuid_str = str(session_uuid) + + test_name = "cli_single" + iri = f"https://example.com?t={test_name}&v={pv()}&s={session_uuid_str}" + + default_hive_operation_id = HiveOperationId( + LIVETEST_OPERATION_ID, Medium.podcast, Reason.update + ) + default_hive_operation_id_str = str(default_hive_operation_id) + + async def get_iri_from_blockchain(start_block: int): + async for post in listen_for_custom_json_operations(client, start_block): + if post["op"][1]["id"] == default_hive_operation_id_str: + data = json.loads(post["op"][1]["json"]) + if "iris" in data and len(data["iris"]) == 1: + yield data["iris"][0] + + args = ["--livetest", "--hive-operation-period", "30", "write", iri] + + current_block = client.get_dynamic_global_properties()["head_block_number"] + + # Ensure hive env vars are set from .env.test file or this will fail + result = runner.invoke(app, args) + + assert result.exit_code == 0 + + iri_found = False + + async for stream_iri in get_iri_from_blockchain(current_block): + if stream_iri == iri: + iri_found = True + break + + assert iri_found diff --git a/tests/regression/test_#56_set_env_to_use_testnet.py b/tests/regression/test_#56_set_env_to_use_testnet.py new file mode 100644 index 0000000..187b2f7 --- /dev/null +++ b/tests/regression/test_#56_set_env_to_use_testnet.py @@ -0,0 +1,75 @@ +import json +import os +import uuid +from platform import python_version as pv + +import pytest +from typer.testing import CliRunner + +from podping_hivewriter.cli.podping import app +from podping_hivewriter.constants import LIVETEST_OPERATION_ID +from podping_hivewriter.hive import get_client, listen_for_custom_json_operations +from podping_hivewriter.models.hive_operation_id import HiveOperationId +from podping_hivewriter.models.medium import Medium +from podping_hivewriter.models.reason import Reason +from podping_hivewriter.podping_settings_manager import PodpingSettingsManager + + +@pytest.mark.asyncio +@pytest.mark.timeout(600) +@pytest.mark.slow +async def test_use_testnet_startup_checks_and_write_cli_single(): + """Uses a testnet if one is available""" + runner = CliRunner() + + os.environ["PODPING_TESTNET"] = "true" + os.environ["PODPING_TESTNET_NODE"] = "https://api.fake.openhive.network" + os.environ[ + "PODPING_TESTNET_CHAINID" + ] = "4200000000000000000000000000000000000000000000000000000000000000" + + client = get_client() + try: + props = client.get_dynamic_global_properties() + except Exception: + # If we can't connect to the fakenet / testnet then just pass the test + assert True + return + + assert props + + session_uuid = uuid.uuid4() + session_uuid_str = str(session_uuid) + + test_name = "use_testnet_startup_checks_and_write_cli_single" + iri = f"https://example.com?t={test_name}&v={pv()}&s={session_uuid_str}" + + default_hive_operation_id = HiveOperationId( + LIVETEST_OPERATION_ID, Medium.podcast, Reason.update + ) + default_hive_operation_id_str = str(default_hive_operation_id) + + async def get_iri_from_blockchain(start_block: int): + async for post in listen_for_custom_json_operations(client, start_block): + if post["op"][1]["id"] == default_hive_operation_id_str: + data = json.loads(post["op"][1]["json"]) + if "iris" in data and len(data["iris"]) == 1: + yield data["iris"][0] + + args = ["--livetest", "--hive-operation-period", "30", "write", iri] + + current_block = client.get_dynamic_global_properties()["head_block_number"] + + # Ensure hive env vars are set from .env.test file or this will fail + result = runner.invoke(app, args) + + assert result.exit_code == 0 + + iri_found = False + + async for stream_iri in get_iri_from_blockchain(current_block): + if stream_iri == iri: + iri_found = True + break + + assert iri_found