├── .dockerignore ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── dockerfile ├── docs ├── Makefile ├── make.bat └── source │ ├── conf.py │ └── index.rst ├── poetry.lock ├── poetry_template ├── __init__.py ├── package_one │ ├── __init__.py │ └── module_one.py ├── package_two │ ├── __init__.py │ └── module_two.py ├── profiler.py ├── runner.py └── settings.py ├── pyproject.toml └── tests ├── __init__.py ├── conftest.py ├── context.py ├── package_one ├── __init__.py └── test_module_one.py └── package_two ├── __init__.py └── test_module_two.py /.dockerignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MislavJaksic/Python-Project-Template/ed90180b36aafd3f2f883d94b6a70e0187ce1b28/.dockerignore -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # IPython 79 | profile_default/ 80 | ipython_config.py 81 | 82 | # pyenv 83 | .python-version 84 | 85 | # pipenv 86 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 87 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 88 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 89 | # install all needed dependencies. 90 | #Pipfile.lock 91 | 92 | # celery beat schedule file 93 | celerybeat-schedule 94 | 95 | # SageMath parsed files 96 | *.sage.py 97 | 98 | # Environments 99 | .env 100 | .venv 101 | env/ 102 | venv/ 103 | ENV/ 104 | env.bak/ 105 | venv.bak/ 106 | 107 | # Spyder project settings 108 | .spyderproject 109 | .spyproject 110 | 111 | # Rope project settings 112 | .ropeproject 113 | 114 | # mkdocs documentation 115 | /site 116 | 117 | # mypy 118 | .mypy_cache/ 119 | .dmypy.json 120 | dmypy.json 121 | 122 | # Pyre type checker 123 | .pyre/ 124 | 125 | # Additional ignore 126 | .idea 127 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 MislavJaksic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Python Project Template 2 | 3 | ``` 4 | After creating a new git repository copy over: 5 | * docs 6 | * poetry_template 7 | * tests 8 | * pyproject.toml 9 | * README.md 10 | 11 | Go through the project and change the placeholder values. pyproject.toml contains the list of the most important values present throughout the project. 12 | 13 | Finally, delete this note. 14 | ``` 15 | 16 | ## Development 17 | 18 | ``` 19 | # Note: Install Python 3 20 | # You may also need to install or update pip, virtualenv (dependency encapsulator) and black (linter) 21 | 22 | # Note: install Poetry for your OS 23 | ``` 24 | 25 | ``` 26 | # Note: `.toml` project name and package have to match (poetry-template; poetry_template) 27 | $: poetry install # install all dependencies 28 | ``` 29 | 30 | ### dist 31 | 32 | ``` 33 | $: pip install dist/poetry_template-0.1.5-py3-none.any.whl 34 | 35 | $: poetry-template 36 | ``` 37 | 38 | ### docs 39 | 40 | ``` 41 | $: poetry shell 42 | $: cd docs 43 | # Note: review source/conf.py and source/index.rst 44 | $: make html 45 | # Note: see docs in docs/build/apidocs/index.html 46 | ``` 47 | 48 | ### poetry_template 49 | 50 | ``` 51 | $: poetry run poetry-template --help 52 | $: poetry run python ./poetry_template/runner.py --help 53 | 54 | $: poetry run python ./poetry_template/runner.py -x 2 -y -1 -tuple A B C -list D -list E -list F -move rock 55 | ``` 56 | 57 | ### tests 58 | 59 | ``` 60 | $: poetry run pytest --durations=0 61 | ``` 62 | 63 | ``` 64 | $: poetry run pytest --cov=poetry_template --cov-report=html tests 65 | # Note: see coverage report in htmlcov/index.html 66 | # Note: exclude directories from coverage report through .coveragerc 67 | ``` 68 | 69 | ### poetry.lock 70 | 71 | Dependencies, Python version and the virtual environment are managed by `Poetry`. 72 | 73 | ``` 74 | $: poetry search Package-Name 75 | $: poetry add [-D] Package-Name[==Package-Version] 76 | ``` 77 | 78 | ### pyproject.toml 79 | 80 | Define project entry point and metadata. 81 | 82 | 83 | ### Linters 84 | 85 | ``` 86 | $: poetry run black . 87 | ``` 88 | 89 | ### MyPy 90 | 91 | ``` 92 | $: poetry run mypy ./poetry_template ./tests 93 | ``` 94 | 95 | ### cProfile 96 | 97 | ``` 98 | $: poetry run python ./poetry_template/profiler.py 99 | ``` 100 | 101 | ### Build and publish 102 | 103 | ``` 104 | $: poetry build 105 | 106 | # Note: get the token from your PiPy account 107 | $: poetry config pypi-token.pypi PyPI-Api-Access-Token 108 | ``` 109 | 110 | ``` 111 | $: poetry publish --build 112 | ``` 113 | 114 | ``` 115 | https://pypi.org/project/poetry-template/ 116 | ``` 117 | -------------------------------------------------------------------------------- /dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | ARG YOUR_ENV 4 | 5 | ENV YOUR_ENV=${YOUR_ENV} \ 6 | PYTHONFAULTHANDLER=1 \ 7 | PYTHONUNBUFFERED=1 \ 8 | PYTHONHASHSEED=random \ 9 | PIP_NO_CACHE_DIR=off \ 10 | PIP_DISABLE_PIP_VERSION_CHECK=on \ 11 | PIP_DEFAULT_TIMEOUT=100 \ 12 | POETRY_VERSION=1.0.0 13 | 14 | # System deps: 15 | RUN pip install "poetry==$POETRY_VERSION" 16 | 17 | # Copy only requirements to cache them in docker layer 18 | COPY poetry.lock pyproject.toml README.md / 19 | 20 | # Project initialization: 21 | RUN poetry config virtualenvs.create false \ 22 | && poetry install $(test "$YOUR_ENV" == production && echo "--no-dev") --no-interaction --no-ansi 23 | 24 | # Creating folders, and files for a project: 25 | COPY /poetry_template /poetry_template -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | sys.path.insert(0, os.path.abspath("../../poetry_template")) 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = "poetry-template" 21 | copyright = "2019, Mislav Jaksic" 22 | author = "Mislav Jaksic" 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = "0.1.5" 26 | 27 | # -- General configuration --------------------------------------------------- 28 | 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | extensions = ["sphinx.ext.autodoc"] 33 | 34 | # Add any paths that contain templates here, relative to this directory. 35 | templates_path = ["_templates"] 36 | 37 | # List of patterns, relative to source directory, that match files and 38 | # directories to ignore when looking for source files. 39 | # This pattern also affects html_static_path and html_extra_path. 40 | exclude_patterns = [] 41 | 42 | # -- Options for HTML output ------------------------------------------------- 43 | 44 | # The theme to use for HTML and HTML Help pages. See the documentation for 45 | # a list of builtin themes. 46 | # 47 | html_theme = "alabaster" 48 | 49 | # Add any paths that contain custom static files (such as style sheets) here, 50 | # relative to this directory. They are copied after the builtin static files, 51 | # so a file named "default.css" will overwrite the builtin "default.css". 52 | html_static_path = ["_static"] 53 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. poetry-template documentation master file, created by 2 | sphinx-quickstart on Wed Sep 4 19:11:00 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to poetry-template's documentation! 7 | =========================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | poetry_template runner 14 | ---------------------- 15 | .. automodule:: runner 16 | :members: 17 | 18 | poetry_template package_one module_one 19 | -------------------------------------- 20 | .. automodule:: package_one.module_one 21 | :members: 22 | 23 | poetry_template package_two module_two 24 | -------------------------------------- 25 | .. automodule:: package_two.module_two 26 | :members: 27 | 28 | 29 | 30 | Indices and tables 31 | ================== 32 | 33 | * :ref:`genindex` 34 | * :ref:`modindex` 35 | * :ref:`search` 36 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "alabaster" 5 | version = "0.7.13" 6 | description = "A configurable sidebar-enabled Sphinx theme" 7 | category = "dev" 8 | optional = false 9 | python-versions = ">=3.6" 10 | files = [ 11 | {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, 12 | {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, 13 | ] 14 | 15 | [[package]] 16 | name = "babel" 17 | version = "2.12.1" 18 | description = "Internationalization utilities" 19 | category = "dev" 20 | optional = false 21 | python-versions = ">=3.7" 22 | files = [ 23 | {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, 24 | {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, 25 | ] 26 | 27 | [package.dependencies] 28 | pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} 29 | 30 | [[package]] 31 | name = "black" 32 | version = "23.3.0" 33 | description = "The uncompromising code formatter." 34 | category = "dev" 35 | optional = false 36 | python-versions = ">=3.7" 37 | files = [ 38 | {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, 39 | {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, 40 | {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, 41 | {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, 42 | {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, 43 | {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, 44 | {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, 45 | {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, 46 | {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, 47 | {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, 48 | {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, 49 | {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, 50 | {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, 51 | {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, 52 | {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, 53 | {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, 54 | {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, 55 | {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, 56 | {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, 57 | {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, 58 | {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, 59 | {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, 60 | {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, 61 | {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, 62 | {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, 63 | ] 64 | 65 | [package.dependencies] 66 | click = ">=8.0.0" 67 | mypy-extensions = ">=0.4.3" 68 | packaging = ">=22.0" 69 | pathspec = ">=0.9.0" 70 | platformdirs = ">=2" 71 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 72 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 73 | 74 | [package.extras] 75 | colorama = ["colorama (>=0.4.3)"] 76 | d = ["aiohttp (>=3.7.4)"] 77 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 78 | uvloop = ["uvloop (>=0.15.2)"] 79 | 80 | [[package]] 81 | name = "certifi" 82 | version = "2022.12.7" 83 | description = "Python package for providing Mozilla's CA Bundle." 84 | category = "main" 85 | optional = false 86 | python-versions = ">=3.6" 87 | files = [ 88 | {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, 89 | {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, 90 | ] 91 | 92 | [[package]] 93 | name = "charset-normalizer" 94 | version = "3.1.0" 95 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 96 | category = "main" 97 | optional = false 98 | python-versions = ">=3.7.0" 99 | files = [ 100 | {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, 101 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, 102 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, 103 | {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, 104 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, 105 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, 106 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, 107 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, 108 | {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, 109 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, 110 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, 111 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, 112 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, 113 | {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, 114 | {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, 115 | {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, 116 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, 117 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, 118 | {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, 119 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, 120 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, 121 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, 122 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, 123 | {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, 124 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, 125 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, 126 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, 127 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, 128 | {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, 129 | {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, 130 | {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, 131 | {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, 132 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, 133 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, 134 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, 135 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, 136 | {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, 137 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, 138 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, 139 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, 140 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, 141 | {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, 142 | {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, 143 | {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, 144 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, 145 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, 146 | {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, 147 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, 148 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, 149 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, 150 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, 151 | {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, 152 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, 153 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, 154 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, 155 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, 156 | {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, 157 | {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, 158 | {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, 159 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, 160 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, 161 | {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, 162 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, 163 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, 164 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, 165 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, 166 | {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, 167 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, 168 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, 169 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, 170 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, 171 | {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, 172 | {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, 173 | {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, 174 | {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, 175 | ] 176 | 177 | [[package]] 178 | name = "click" 179 | version = "8.1.3" 180 | description = "Composable command line interface toolkit" 181 | category = "dev" 182 | optional = false 183 | python-versions = ">=3.7" 184 | files = [ 185 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 186 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 187 | ] 188 | 189 | [package.dependencies] 190 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 191 | 192 | [[package]] 193 | name = "colorama" 194 | version = "0.4.6" 195 | description = "Cross-platform colored terminal text." 196 | category = "main" 197 | optional = false 198 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 199 | files = [ 200 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 201 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 202 | ] 203 | 204 | [[package]] 205 | name = "coverage" 206 | version = "7.2.3" 207 | description = "Code coverage measurement for Python" 208 | category = "dev" 209 | optional = false 210 | python-versions = ">=3.7" 211 | files = [ 212 | {file = "coverage-7.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5"}, 213 | {file = "coverage-7.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4"}, 214 | {file = "coverage-7.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2"}, 215 | {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013"}, 216 | {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa"}, 217 | {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b"}, 218 | {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257"}, 219 | {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535"}, 220 | {file = "coverage-7.2.3-cp310-cp310-win32.whl", hash = "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91"}, 221 | {file = "coverage-7.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e"}, 222 | {file = "coverage-7.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79"}, 223 | {file = "coverage-7.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc"}, 224 | {file = "coverage-7.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df"}, 225 | {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623"}, 226 | {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d"}, 227 | {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93"}, 228 | {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312"}, 229 | {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4"}, 230 | {file = "coverage-7.2.3-cp311-cp311-win32.whl", hash = "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925"}, 231 | {file = "coverage-7.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910"}, 232 | {file = "coverage-7.2.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c"}, 233 | {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9"}, 234 | {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1"}, 235 | {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1"}, 236 | {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21"}, 237 | {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841"}, 238 | {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48"}, 239 | {file = "coverage-7.2.3-cp37-cp37m-win32.whl", hash = "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1"}, 240 | {file = "coverage-7.2.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f"}, 241 | {file = "coverage-7.2.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab"}, 242 | {file = "coverage-7.2.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040"}, 243 | {file = "coverage-7.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1"}, 244 | {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911"}, 245 | {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462"}, 246 | {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c"}, 247 | {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd"}, 248 | {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152"}, 249 | {file = "coverage-7.2.3-cp38-cp38-win32.whl", hash = "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22"}, 250 | {file = "coverage-7.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367"}, 251 | {file = "coverage-7.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235"}, 252 | {file = "coverage-7.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21"}, 253 | {file = "coverage-7.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934"}, 254 | {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859"}, 255 | {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9"}, 256 | {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539"}, 257 | {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe"}, 258 | {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4"}, 259 | {file = "coverage-7.2.3-cp39-cp39-win32.whl", hash = "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30"}, 260 | {file = "coverage-7.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a"}, 261 | {file = "coverage-7.2.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0"}, 262 | {file = "coverage-7.2.3.tar.gz", hash = "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259"}, 263 | ] 264 | 265 | [package.dependencies] 266 | tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} 267 | 268 | [package.extras] 269 | toml = ["tomli"] 270 | 271 | [[package]] 272 | name = "docutils" 273 | version = "0.19" 274 | description = "Docutils -- Python Documentation Utilities" 275 | category = "dev" 276 | optional = false 277 | python-versions = ">=3.7" 278 | files = [ 279 | {file = "docutils-0.19-py3-none-any.whl", hash = "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"}, 280 | {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"}, 281 | ] 282 | 283 | [[package]] 284 | name = "exceptiongroup" 285 | version = "1.1.1" 286 | description = "Backport of PEP 654 (exception groups)" 287 | category = "dev" 288 | optional = false 289 | python-versions = ">=3.7" 290 | files = [ 291 | {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, 292 | {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, 293 | ] 294 | 295 | [package.extras] 296 | test = ["pytest (>=6)"] 297 | 298 | [[package]] 299 | name = "idna" 300 | version = "3.4" 301 | description = "Internationalized Domain Names in Applications (IDNA)" 302 | category = "main" 303 | optional = false 304 | python-versions = ">=3.5" 305 | files = [ 306 | {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, 307 | {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, 308 | ] 309 | 310 | [[package]] 311 | name = "imagesize" 312 | version = "1.4.1" 313 | description = "Getting image size from png/jpeg/jpeg2000/gif file" 314 | category = "dev" 315 | optional = false 316 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 317 | files = [ 318 | {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, 319 | {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, 320 | ] 321 | 322 | [[package]] 323 | name = "importlib-metadata" 324 | version = "6.3.0" 325 | description = "Read metadata from Python packages" 326 | category = "dev" 327 | optional = false 328 | python-versions = ">=3.7" 329 | files = [ 330 | {file = "importlib_metadata-6.3.0-py3-none-any.whl", hash = "sha256:8f8bd2af397cf33bd344d35cfe7f489219b7d14fc79a3f854b75b8417e9226b0"}, 331 | {file = "importlib_metadata-6.3.0.tar.gz", hash = "sha256:23c2bcae4762dfb0bbe072d358faec24957901d75b6c4ab11172c0c982532402"}, 332 | ] 333 | 334 | [package.dependencies] 335 | zipp = ">=0.5" 336 | 337 | [package.extras] 338 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 339 | perf = ["ipython"] 340 | testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] 341 | 342 | [[package]] 343 | name = "iniconfig" 344 | version = "2.0.0" 345 | description = "brain-dead simple config-ini parsing" 346 | category = "dev" 347 | optional = false 348 | python-versions = ">=3.7" 349 | files = [ 350 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 351 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 352 | ] 353 | 354 | [[package]] 355 | name = "jinja2" 356 | version = "3.1.2" 357 | description = "A very fast and expressive template engine." 358 | category = "dev" 359 | optional = false 360 | python-versions = ">=3.7" 361 | files = [ 362 | {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, 363 | {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, 364 | ] 365 | 366 | [package.dependencies] 367 | MarkupSafe = ">=2.0" 368 | 369 | [package.extras] 370 | i18n = ["Babel (>=2.7)"] 371 | 372 | [[package]] 373 | name = "loguru" 374 | version = "0.7.0" 375 | description = "Python logging made (stupidly) simple" 376 | category = "main" 377 | optional = false 378 | python-versions = ">=3.5" 379 | files = [ 380 | {file = "loguru-0.7.0-py3-none-any.whl", hash = "sha256:b93aa30099fa6860d4727f1b81f8718e965bb96253fa190fab2077aaad6d15d3"}, 381 | {file = "loguru-0.7.0.tar.gz", hash = "sha256:1612053ced6ae84d7959dd7d5e431a0532642237ec21f7fd83ac73fe539e03e1"}, 382 | ] 383 | 384 | [package.dependencies] 385 | colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} 386 | win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} 387 | 388 | [package.extras] 389 | dev = ["Sphinx (==5.3.0)", "colorama (==0.4.5)", "colorama (==0.4.6)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v0.990)", "pre-commit (==3.2.1)", "pytest (==6.1.2)", "pytest (==7.2.1)", "pytest-cov (==2.12.1)", "pytest-cov (==4.0.0)", "pytest-mypy-plugins (==1.10.1)", "pytest-mypy-plugins (==1.9.3)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.2.0)", "tox (==3.27.1)", "tox (==4.4.6)"] 390 | 391 | [[package]] 392 | name = "markupsafe" 393 | version = "2.1.2" 394 | description = "Safely add untrusted strings to HTML/XML markup." 395 | category = "dev" 396 | optional = false 397 | python-versions = ">=3.7" 398 | files = [ 399 | {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, 400 | {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, 401 | {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, 402 | {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, 403 | {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, 404 | {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, 405 | {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, 406 | {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, 407 | {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, 408 | {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, 409 | {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, 410 | {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, 411 | {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, 412 | {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, 413 | {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, 414 | {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, 415 | {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, 416 | {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, 417 | {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, 418 | {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, 419 | {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, 420 | {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, 421 | {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, 422 | {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, 423 | {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, 424 | {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, 425 | {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, 426 | {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, 427 | {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, 428 | {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, 429 | {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, 430 | {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, 431 | {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, 432 | {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, 433 | {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, 434 | {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, 435 | {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, 436 | {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, 437 | {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, 438 | {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, 439 | {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, 440 | {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, 441 | {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, 442 | {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, 443 | {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, 444 | {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, 445 | {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, 446 | {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, 447 | {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, 448 | {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, 449 | ] 450 | 451 | [[package]] 452 | name = "mypy" 453 | version = "1.2.0" 454 | description = "Optional static typing for Python" 455 | category = "dev" 456 | optional = false 457 | python-versions = ">=3.7" 458 | files = [ 459 | {file = "mypy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:701189408b460a2ff42b984e6bd45c3f41f0ac9f5f58b8873bbedc511900086d"}, 460 | {file = "mypy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fe91be1c51c90e2afe6827601ca14353bbf3953f343c2129fa1e247d55fd95ba"}, 461 | {file = "mypy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d26b513225ffd3eacece727f4387bdce6469192ef029ca9dd469940158bc89e"}, 462 | {file = "mypy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a2d219775a120581a0ae8ca392b31f238d452729adbcb6892fa89688cb8306a"}, 463 | {file = "mypy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:2e93a8a553e0394b26c4ca683923b85a69f7ccdc0139e6acd1354cc884fe0128"}, 464 | {file = "mypy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3efde4af6f2d3ccf58ae825495dbb8d74abd6d176ee686ce2ab19bd025273f41"}, 465 | {file = "mypy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:695c45cea7e8abb6f088a34a6034b1d273122e5530aeebb9c09626cea6dca4cb"}, 466 | {file = "mypy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0e9464a0af6715852267bf29c9553e4555b61f5904a4fc538547a4d67617937"}, 467 | {file = "mypy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8293a216e902ac12779eb7a08f2bc39ec6c878d7c6025aa59464e0c4c16f7eb9"}, 468 | {file = "mypy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:f46af8d162f3d470d8ffc997aaf7a269996d205f9d746124a179d3abe05ac602"}, 469 | {file = "mypy-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:031fc69c9a7e12bcc5660b74122ed84b3f1c505e762cc4296884096c6d8ee140"}, 470 | {file = "mypy-1.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:390bc685ec209ada4e9d35068ac6988c60160b2b703072d2850457b62499e336"}, 471 | {file = "mypy-1.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4b41412df69ec06ab141808d12e0bf2823717b1c363bd77b4c0820feaa37249e"}, 472 | {file = "mypy-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4e4a682b3f2489d218751981639cffc4e281d548f9d517addfd5a2917ac78119"}, 473 | {file = "mypy-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a197ad3a774f8e74f21e428f0de7f60ad26a8d23437b69638aac2764d1e06a6a"}, 474 | {file = "mypy-1.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c9a084bce1061e55cdc0493a2ad890375af359c766b8ac311ac8120d3a472950"}, 475 | {file = "mypy-1.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaeaa0888b7f3ccb7bcd40b50497ca30923dba14f385bde4af78fac713d6d6f6"}, 476 | {file = "mypy-1.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bea55fc25b96c53affab852ad94bf111a3083bc1d8b0c76a61dd101d8a388cf5"}, 477 | {file = "mypy-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:4c8d8c6b80aa4a1689f2a179d31d86ae1367ea4a12855cc13aa3ba24bb36b2d8"}, 478 | {file = "mypy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:70894c5345bea98321a2fe84df35f43ee7bb0feec117a71420c60459fc3e1eed"}, 479 | {file = "mypy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a99fe1768925e4a139aace8f3fb66db3576ee1c30b9c0f70f744ead7e329c9f"}, 480 | {file = "mypy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023fe9e618182ca6317ae89833ba422c411469156b690fde6a315ad10695a521"}, 481 | {file = "mypy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4d19f1a239d59f10fdc31263d48b7937c585810288376671eaf75380b074f238"}, 482 | {file = "mypy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:2de7babe398cb7a85ac7f1fd5c42f396c215ab3eff731b4d761d68d0f6a80f48"}, 483 | {file = "mypy-1.2.0-py3-none-any.whl", hash = "sha256:d8e9187bfcd5ffedbe87403195e1fc340189a68463903c39e2b63307c9fa0394"}, 484 | {file = "mypy-1.2.0.tar.gz", hash = "sha256:f70a40410d774ae23fcb4afbbeca652905a04de7948eaf0b1789c8d1426b72d1"}, 485 | ] 486 | 487 | [package.dependencies] 488 | mypy-extensions = ">=1.0.0" 489 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 490 | typing-extensions = ">=3.10" 491 | 492 | [package.extras] 493 | dmypy = ["psutil (>=4.0)"] 494 | install-types = ["pip"] 495 | python2 = ["typed-ast (>=1.4.0,<2)"] 496 | reports = ["lxml"] 497 | 498 | [[package]] 499 | name = "mypy-extensions" 500 | version = "1.0.0" 501 | description = "Type system extensions for programs checked with the mypy type checker." 502 | category = "dev" 503 | optional = false 504 | python-versions = ">=3.5" 505 | files = [ 506 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 507 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 508 | ] 509 | 510 | [[package]] 511 | name = "packaging" 512 | version = "23.0" 513 | description = "Core utilities for Python packages" 514 | category = "dev" 515 | optional = false 516 | python-versions = ">=3.7" 517 | files = [ 518 | {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, 519 | {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, 520 | ] 521 | 522 | [[package]] 523 | name = "pathspec" 524 | version = "0.11.1" 525 | description = "Utility library for gitignore style pattern matching of file paths." 526 | category = "dev" 527 | optional = false 528 | python-versions = ">=3.7" 529 | files = [ 530 | {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, 531 | {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, 532 | ] 533 | 534 | [[package]] 535 | name = "platformdirs" 536 | version = "3.2.0" 537 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 538 | category = "dev" 539 | optional = false 540 | python-versions = ">=3.7" 541 | files = [ 542 | {file = "platformdirs-3.2.0-py3-none-any.whl", hash = "sha256:ebe11c0d7a805086e99506aa331612429a72ca7cd52a1f0d277dc4adc20cb10e"}, 543 | {file = "platformdirs-3.2.0.tar.gz", hash = "sha256:d5b638ca397f25f979350ff789db335903d7ea010ab28903f57b27e1b16c2b08"}, 544 | ] 545 | 546 | [package.extras] 547 | docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] 548 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] 549 | 550 | [[package]] 551 | name = "pluggy" 552 | version = "1.0.0" 553 | description = "plugin and hook calling mechanisms for python" 554 | category = "dev" 555 | optional = false 556 | python-versions = ">=3.6" 557 | files = [ 558 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 559 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 560 | ] 561 | 562 | [package.extras] 563 | dev = ["pre-commit", "tox"] 564 | testing = ["pytest", "pytest-benchmark"] 565 | 566 | [[package]] 567 | name = "pygments" 568 | version = "2.15.0" 569 | description = "Pygments is a syntax highlighting package written in Python." 570 | category = "dev" 571 | optional = false 572 | python-versions = ">=3.7" 573 | files = [ 574 | {file = "Pygments-2.15.0-py3-none-any.whl", hash = "sha256:77a3299119af881904cd5ecd1ac6a66214b6e9bed1f2db16993b54adede64094"}, 575 | {file = "Pygments-2.15.0.tar.gz", hash = "sha256:f7e36cffc4c517fbc252861b9a6e4644ca0e5abadf9a113c72d1358ad09b9500"}, 576 | ] 577 | 578 | [package.extras] 579 | plugins = ["importlib-metadata"] 580 | 581 | [[package]] 582 | name = "pytest" 583 | version = "7.3.0" 584 | description = "pytest: simple powerful testing with Python" 585 | category = "dev" 586 | optional = false 587 | python-versions = ">=3.7" 588 | files = [ 589 | {file = "pytest-7.3.0-py3-none-any.whl", hash = "sha256:933051fa1bfbd38a21e73c3960cebdad4cf59483ddba7696c48509727e17f201"}, 590 | {file = "pytest-7.3.0.tar.gz", hash = "sha256:58ecc27ebf0ea643ebfdf7fb1249335da761a00c9f955bcd922349bcb68ee57d"}, 591 | ] 592 | 593 | [package.dependencies] 594 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 595 | exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} 596 | iniconfig = "*" 597 | packaging = "*" 598 | pluggy = ">=0.12,<2.0" 599 | tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} 600 | 601 | [package.extras] 602 | testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 603 | 604 | [[package]] 605 | name = "pytest-asyncio" 606 | version = "0.21.0" 607 | description = "Pytest support for asyncio" 608 | category = "dev" 609 | optional = false 610 | python-versions = ">=3.7" 611 | files = [ 612 | {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, 613 | {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, 614 | ] 615 | 616 | [package.dependencies] 617 | pytest = ">=7.0.0" 618 | 619 | [package.extras] 620 | docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] 621 | testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] 622 | 623 | [[package]] 624 | name = "pytest-cov" 625 | version = "4.0.0" 626 | description = "Pytest plugin for measuring coverage." 627 | category = "dev" 628 | optional = false 629 | python-versions = ">=3.6" 630 | files = [ 631 | {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, 632 | {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, 633 | ] 634 | 635 | [package.dependencies] 636 | coverage = {version = ">=5.2.1", extras = ["toml"]} 637 | pytest = ">=4.6" 638 | 639 | [package.extras] 640 | testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] 641 | 642 | [[package]] 643 | name = "pytest-integration" 644 | version = "0.2.3" 645 | description = "Organizing pytests by integration or not" 646 | category = "dev" 647 | optional = false 648 | python-versions = ">=3.6" 649 | files = [ 650 | {file = "pytest_integration-0.2.3-py3-none-any.whl", hash = "sha256:7f59ed1fa1cc8cb240f9495b68bc02c0421cce48589f78e49b7b842231604b12"}, 651 | {file = "pytest_integration-0.2.3.tar.gz", hash = "sha256:b00988a5de8a6826af82d4c7a3485b43fbf32c11235e9f4a8b7225eef5fbcf65"}, 652 | ] 653 | 654 | [[package]] 655 | name = "pytz" 656 | version = "2023.3" 657 | description = "World timezone definitions, modern and historical" 658 | category = "dev" 659 | optional = false 660 | python-versions = "*" 661 | files = [ 662 | {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, 663 | {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, 664 | ] 665 | 666 | [[package]] 667 | name = "requests" 668 | version = "2.28.2" 669 | description = "Python HTTP for Humans." 670 | category = "main" 671 | optional = false 672 | python-versions = ">=3.7, <4" 673 | files = [ 674 | {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, 675 | {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, 676 | ] 677 | 678 | [package.dependencies] 679 | certifi = ">=2017.4.17" 680 | charset-normalizer = ">=2,<4" 681 | idna = ">=2.5,<4" 682 | urllib3 = ">=1.21.1,<1.27" 683 | 684 | [package.extras] 685 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 686 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] 687 | 688 | [[package]] 689 | name = "snowballstemmer" 690 | version = "2.2.0" 691 | description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." 692 | category = "dev" 693 | optional = false 694 | python-versions = "*" 695 | files = [ 696 | {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, 697 | {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, 698 | ] 699 | 700 | [[package]] 701 | name = "sphinx" 702 | version = "5.3.0" 703 | description = "Python documentation generator" 704 | category = "dev" 705 | optional = false 706 | python-versions = ">=3.6" 707 | files = [ 708 | {file = "Sphinx-5.3.0.tar.gz", hash = "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5"}, 709 | {file = "sphinx-5.3.0-py3-none-any.whl", hash = "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d"}, 710 | ] 711 | 712 | [package.dependencies] 713 | alabaster = ">=0.7,<0.8" 714 | babel = ">=2.9" 715 | colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} 716 | docutils = ">=0.14,<0.20" 717 | imagesize = ">=1.3" 718 | importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} 719 | Jinja2 = ">=3.0" 720 | packaging = ">=21.0" 721 | Pygments = ">=2.12" 722 | requests = ">=2.5.0" 723 | snowballstemmer = ">=2.0" 724 | sphinxcontrib-applehelp = "*" 725 | sphinxcontrib-devhelp = "*" 726 | sphinxcontrib-htmlhelp = ">=2.0.0" 727 | sphinxcontrib-jsmath = "*" 728 | sphinxcontrib-qthelp = "*" 729 | sphinxcontrib-serializinghtml = ">=1.1.5" 730 | 731 | [package.extras] 732 | docs = ["sphinxcontrib-websupport"] 733 | lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"] 734 | test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"] 735 | 736 | [[package]] 737 | name = "sphinxcontrib-applehelp" 738 | version = "1.0.4" 739 | description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" 740 | category = "dev" 741 | optional = false 742 | python-versions = ">=3.8" 743 | files = [ 744 | {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, 745 | {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, 746 | ] 747 | 748 | [package.extras] 749 | lint = ["docutils-stubs", "flake8", "mypy"] 750 | test = ["pytest"] 751 | 752 | [[package]] 753 | name = "sphinxcontrib-devhelp" 754 | version = "1.0.2" 755 | description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." 756 | category = "dev" 757 | optional = false 758 | python-versions = ">=3.5" 759 | files = [ 760 | {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, 761 | {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, 762 | ] 763 | 764 | [package.extras] 765 | lint = ["docutils-stubs", "flake8", "mypy"] 766 | test = ["pytest"] 767 | 768 | [[package]] 769 | name = "sphinxcontrib-htmlhelp" 770 | version = "2.0.1" 771 | description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" 772 | category = "dev" 773 | optional = false 774 | python-versions = ">=3.8" 775 | files = [ 776 | {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, 777 | {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, 778 | ] 779 | 780 | [package.extras] 781 | lint = ["docutils-stubs", "flake8", "mypy"] 782 | test = ["html5lib", "pytest"] 783 | 784 | [[package]] 785 | name = "sphinxcontrib-jsmath" 786 | version = "1.0.1" 787 | description = "A sphinx extension which renders display math in HTML via JavaScript" 788 | category = "dev" 789 | optional = false 790 | python-versions = ">=3.5" 791 | files = [ 792 | {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, 793 | {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, 794 | ] 795 | 796 | [package.extras] 797 | test = ["flake8", "mypy", "pytest"] 798 | 799 | [[package]] 800 | name = "sphinxcontrib-qthelp" 801 | version = "1.0.3" 802 | description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." 803 | category = "dev" 804 | optional = false 805 | python-versions = ">=3.5" 806 | files = [ 807 | {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, 808 | {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, 809 | ] 810 | 811 | [package.extras] 812 | lint = ["docutils-stubs", "flake8", "mypy"] 813 | test = ["pytest"] 814 | 815 | [[package]] 816 | name = "sphinxcontrib-serializinghtml" 817 | version = "1.1.5" 818 | description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." 819 | category = "dev" 820 | optional = false 821 | python-versions = ">=3.5" 822 | files = [ 823 | {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, 824 | {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, 825 | ] 826 | 827 | [package.extras] 828 | lint = ["docutils-stubs", "flake8", "mypy"] 829 | test = ["pytest"] 830 | 831 | [[package]] 832 | name = "tomli" 833 | version = "2.0.1" 834 | description = "A lil' TOML parser" 835 | category = "dev" 836 | optional = false 837 | python-versions = ">=3.7" 838 | files = [ 839 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 840 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 841 | ] 842 | 843 | [[package]] 844 | name = "typing-extensions" 845 | version = "4.5.0" 846 | description = "Backported and Experimental Type Hints for Python 3.7+" 847 | category = "dev" 848 | optional = false 849 | python-versions = ">=3.7" 850 | files = [ 851 | {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, 852 | {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, 853 | ] 854 | 855 | [[package]] 856 | name = "urllib3" 857 | version = "1.26.15" 858 | description = "HTTP library with thread-safe connection pooling, file post, and more." 859 | category = "main" 860 | optional = false 861 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 862 | files = [ 863 | {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, 864 | {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, 865 | ] 866 | 867 | [package.extras] 868 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] 869 | secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] 870 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 871 | 872 | [[package]] 873 | name = "win32-setctime" 874 | version = "1.1.0" 875 | description = "A small Python utility to set file creation time on Windows" 876 | category = "main" 877 | optional = false 878 | python-versions = ">=3.5" 879 | files = [ 880 | {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, 881 | {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, 882 | ] 883 | 884 | [package.extras] 885 | dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] 886 | 887 | [[package]] 888 | name = "zipp" 889 | version = "3.15.0" 890 | description = "Backport of pathlib-compatible object wrapper for zip files" 891 | category = "dev" 892 | optional = false 893 | python-versions = ">=3.7" 894 | files = [ 895 | {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, 896 | {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, 897 | ] 898 | 899 | [package.extras] 900 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 901 | testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] 902 | 903 | [metadata] 904 | lock-version = "2.0" 905 | python-versions = "^3.8" 906 | content-hash = "2d08fc61cdb75e55e9cc0f1f111986e8f60c3486aac4b828463c81421876006b" 907 | -------------------------------------------------------------------------------- /poetry_template/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MislavJaksic/Python-Project-Template/ed90180b36aafd3f2f883d94b6a70e0187ce1b28/poetry_template/__init__.py -------------------------------------------------------------------------------- /poetry_template/package_one/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MislavJaksic/Python-Project-Template/ed90180b36aafd3f2f883d94b6a70e0187ce1b28/poetry_template/package_one/__init__.py -------------------------------------------------------------------------------- /poetry_template/package_one/module_one.py: -------------------------------------------------------------------------------- 1 | """ 2 | Application module. 3 | """ 4 | from typing import ClassVar 5 | 6 | from poetry_template import settings 7 | from poetry_template.package_two import module_two 8 | 9 | 10 | def get_setting(): 11 | return settings.filename 12 | 13 | 14 | def add(x: int, y: int) -> int: 15 | """ 16 | Add two numbers using a library. 17 | 18 | :param x: first whole number 19 | :param y: second whole number 20 | """ 21 | return module_two.add_two_numbers(x, y) 22 | 23 | 24 | def multiply(x: int, y: int) -> int: 25 | """ 26 | Multiply two numbers using a library. 27 | 28 | :param x: first whole number 29 | :param y: second whole number 30 | """ 31 | return module_two.multiply_two_numbers(x, y) 32 | 33 | 34 | def raise_exception(): 35 | """Raise an exception.""" 36 | raise SystemExit(1) 37 | 38 | 39 | class Calculator: 40 | class_field: ClassVar[str] = "class_value" 41 | instance_field: str 42 | 43 | def __init__(self, instance_value: str): 44 | self.instance_field = instance_value 45 | 46 | def multiply(self, a: int, b: int) -> int: 47 | return a * b 48 | -------------------------------------------------------------------------------- /poetry_template/package_two/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MislavJaksic/Python-Project-Template/ed90180b36aafd3f2f883d94b6a70e0187ce1b28/poetry_template/package_two/__init__.py -------------------------------------------------------------------------------- /poetry_template/package_two/module_two.py: -------------------------------------------------------------------------------- 1 | """ 2 | Library module. 3 | """ 4 | 5 | 6 | def add_two_numbers(x: int, y: int) -> int: 7 | """ 8 | Add two numbers. 9 | 10 | :param x: first whole number 11 | :param y: second whole number 12 | """ 13 | return x + y 14 | 15 | 16 | def multiply_two_numbers(x: int, y: int) -> int: 17 | """ 18 | Multiply two numbers. 19 | 20 | :param x: first whole number 21 | :param y: second whole number 22 | """ 23 | return x * y 24 | -------------------------------------------------------------------------------- /poetry_template/profiler.py: -------------------------------------------------------------------------------- 1 | import cProfile 2 | 3 | import runner # noqa 4 | 5 | cProfile.run("runner.main(None)") 6 | -------------------------------------------------------------------------------- /poetry_template/runner.py: -------------------------------------------------------------------------------- 1 | """ 2 | poetry-template.py 3 | ------------------ 4 | 5 | Runs the project. 6 | 7 | :copyright: 2019 MislavJaksic 8 | :license: MIT License 9 | """ 10 | import argparse 11 | import socket 12 | import sys 13 | from typing import Dict, Any 14 | 15 | from loguru import logger 16 | 17 | from poetry_template.package_one import module_one 18 | from poetry_template.package_one.module_one import raise_exception 19 | 20 | log_message = "who={username}, what={object}/{status}" 21 | 22 | 23 | def main() -> int: 24 | """main() will be run if you run this script directly""" 25 | args = get_cli_arguments() 26 | 27 | setup_loguru() 28 | try: 29 | raise_exception() 30 | except: 31 | logger.exception(log_message, username="1", object=2, status=3) 32 | 33 | print("Command line interface arguments:{}".format(args)) 34 | x = args["first"] 35 | y = args["second"] 36 | 37 | print(module_one.add(x, y)) 38 | print(module_one.multiply(x, y)) 39 | 40 | return 0 41 | 42 | 43 | def get_cli_arguments() -> Dict[str, Any]: 44 | parser = argparse.ArgumentParser(description="Welcome to the command line interface!", 45 | epilog="Thank you for using the program!") 46 | 47 | parser.add_argument("-x", "--first", type=int, required=True, help="First number") 48 | parser.add_argument("-y", "--second", type=int, required=True, help="Second number") 49 | parser.add_argument("-o", "--optional", type=int, nargs='?', const=1, default=1, help="Optional number") 50 | parser.add_argument("-list", "--multiple", action="append", help="Can be specified many times") 51 | parser.add_argument("-tuple", "--triple", nargs=3, metavar=("password", "username", "secret"), 52 | help="(password, username, secret) tuple") 53 | parser.add_argument("-move", "--move", choices=["rock", "paper", "scissors"], help="Can only input a choice") 54 | 55 | return vars(parser.parse_args()) 56 | 57 | 58 | def setup_loguru() -> None: 59 | host = socket.gethostname() 60 | ip = socket.gethostbyname(host) 61 | 62 | config = { 63 | "handlers": [ 64 | {"sink": sys.stderr, "diagnose": False, 65 | "format": '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {extra[host]}:{extra[ip]} | {process}:{thread} | {module}:{name}:{function}:{line} | {message}'}, 66 | # {"sink": "file.log", "retention": "7 days", "compression": "zip", "serialize": True}, 67 | ], 68 | "extra": {"host": host, "ip": ip}, 69 | } 70 | 71 | logger.configure(**config) # type: ignore 72 | 73 | 74 | def run() -> None: 75 | """Entry point for the runnable script.""" 76 | sys.exit(main()) 77 | 78 | 79 | if __name__ == "__main__": 80 | """main calls run().""" 81 | run() 82 | -------------------------------------------------------------------------------- /poetry_template/settings.py: -------------------------------------------------------------------------------- 1 | filename = "text.txt" 2 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "poetry-template" 3 | version = "0.1.5" 4 | description = "A minimal, strictly structured Python project template." 5 | 6 | license = "MIT" 7 | authors = ["Mislav Jaksic "] 8 | maintainers = [] 9 | readme = "README.md" 10 | 11 | homepage = "https://github.com/MislavJaksic/Python-Project-Template" 12 | repository = "https://github.com/MislavJaksic/Python-Project-Template" 13 | documentation = "https://github.com/MislavJaksic/Python-Project-Template" 14 | 15 | keywords = [] 16 | 17 | classifiers = [] 18 | 19 | [tool.poetry.dependencies] 20 | python = "^3.8" 21 | requests = "^2.28.2" 22 | loguru = "^0.7.0" 23 | 24 | [tool.poetry.dev-dependencies] 25 | pytest-cov = "^4.0.0" 26 | pytest = "^7.3.0" 27 | pytest-asyncio = "^0.21.0" 28 | pytest-integration = "0.2.3" 29 | Sphinx = "^5.0.0" 30 | black = "^23.3.0" 31 | mypy = "^1.2.0" 32 | 33 | [tool.poetry.scripts] 34 | poetry-template = "poetry_template.runner:run" 35 | 36 | [tool.mypy] 37 | python_version = "3.8" 38 | ignore_missing_imports = true 39 | # plugins = pydantic.mypy 40 | 41 | [tool.pytest.ini_options] 42 | asyncio_mode = "auto" 43 | testpaths = "tests" 44 | 45 | [build-system] 46 | requires = ["poetry>=0.12"] 47 | build-backend = "poetry.masonry.api" 48 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MislavJaksic/Python-Project-Template/ed90180b36aafd3f2f883d94b6a70e0187ce1b28/tests/__init__.py -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # pytest only exposes fixtures in a file called conftest.py! 2 | 3 | import pytest 4 | 5 | 6 | @pytest.fixture(scope="package") 7 | def package_level(): 8 | yield 1 9 | 10 | 11 | @pytest.fixture(scope="session") 12 | def session_level(): 13 | yield 1 14 | -------------------------------------------------------------------------------- /tests/context.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | # Adds "poetry_template" to sys.path 5 | # Now you can do import with "from poetry_template.Sub-Package ..." 6 | sys.path.insert( 7 | 0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "poetry_template")) 8 | ) 9 | -------------------------------------------------------------------------------- /tests/package_one/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MislavJaksic/Python-Project-Template/ed90180b36aafd3f2f883d94b6a70e0187ce1b28/tests/package_one/__init__.py -------------------------------------------------------------------------------- /tests/package_one/test_module_one.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from poetry_template.package_one import module_one 4 | from poetry_template.package_one.module_one import add 5 | from poetry_template.package_two import module_two 6 | 7 | 8 | @pytest.fixture(scope="function") 9 | def basic_array(): 10 | # setup 11 | yield [x for x in range(5)] 12 | # teardown 13 | 14 | 15 | @pytest.fixture(scope="module") 16 | def complex_array(): 17 | yield [x for x in range(5)] 18 | 19 | 20 | def test_get_setting(): 21 | assert module_one.get_setting() == "text.txt" 22 | 23 | 24 | @pytest.fixture(scope="function") 25 | def calculator(): 26 | # setup 27 | calculator = module_one.Calculator("instance_value") # must be imported through module_one due to mocking! 28 | yield calculator 29 | # teardown 30 | 31 | 32 | class MockAdd: # used for mocking complex objects 33 | @staticmethod 34 | def ten(): 35 | return 10 36 | 37 | 38 | @pytest.fixture(scope="function") 39 | def mock_add(monkeypatch): 40 | def mock(*args, **kwargs): 41 | return MockAdd().ten() 42 | 43 | monkeypatch.setattr(module_two, "add_two_numbers", mock) 44 | 45 | 46 | class MockCalculator: # used for mocking complex objects 47 | @staticmethod 48 | def multiply(a, b): 49 | return 99 50 | 51 | 52 | @pytest.fixture(scope="function") 53 | def mock_calculator(monkeypatch): 54 | def mock(*args, **kwargs): 55 | return MockCalculator() 56 | 57 | monkeypatch.setattr(module_one, "Calculator", mock) 58 | 59 | 60 | class TestClassForModuleOne: 61 | def test_add(self): 62 | assert module_one.add(1, 5) == 6 63 | 64 | def test_raise_exception(self): 65 | with pytest.raises(SystemExit): 66 | module_one.raise_exception() 67 | 68 | 69 | def test_temporary_directory_file(tmp_path): 70 | dir = tmp_path / "sub_dir" 71 | dir.mkdir() 72 | dir_file = dir / "file.txt" 73 | dir_file.write_text("hello world") # instantiates the file 74 | dir_file.write_text("world, hello") 75 | 76 | assert len(list(tmp_path.iterdir())) == 1 77 | assert dir_file.exists() == True 78 | 79 | assert dir_file.read_text() == "world, hello" 80 | 81 | 82 | def test_manipulate_array(basic_array): 83 | assert len(basic_array) == 5 84 | 85 | 86 | class TestCalculator: 87 | # def __init__(self): # Forbidden by pytest! Use fixtures instead 88 | # self.calculator = module_one.Calculator("instance_value") 89 | 90 | def test_multiply(self, calculator): 91 | assert calculator.multiply(1, 2) == 2 92 | 93 | 94 | class TestMockCalculator: 95 | def test_multiply_mock(self, mock_calculator, calculator): # mock_calculator must come before the real Class! 96 | assert calculator.multiply(1, 2) == 99 97 | 98 | 99 | class TestAddMock: 100 | def test_add_mock(self, mock_add): 101 | result = add(1, 1) 102 | assert result == 10 103 | -------------------------------------------------------------------------------- /tests/package_two/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MislavJaksic/Python-Project-Template/ed90180b36aafd3f2f883d94b6a70e0187ce1b28/tests/package_two/__init__.py -------------------------------------------------------------------------------- /tests/package_two/test_module_two.py: -------------------------------------------------------------------------------- 1 | from poetry_template.package_two import module_two 2 | 3 | 4 | class TestClassForModuleTwo: 5 | def test_add_two_numbers(self): 6 | assert module_two.add_two_numbers(1, 5) == 6 7 | 8 | def test_multiply_two_numbers(self): 9 | assert module_two.multiply_two_numbers(2, 4) == 8 10 | --------------------------------------------------------------------------------