diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c447f34..bdfda45 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,8 +11,8 @@ jobs: strategy: fail-fast: false matrix: - python: ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10"] - toxenv: [py] + python: ["3.6", "3.7", "3.8", "3.9", "3.10"] + toxenv: [py, py-type] include: - python: "3.10" toxenv: flake8 diff --git a/poetry.lock b/poetry.lock index b7d1e5b..c3f190a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,6 +1,6 @@ [[package]] name = "appnope" -version = "0.1.2" +version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" category = "dev" optional = false @@ -16,17 +16,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "21.2.0" +version = "21.4.0" description = "Classes Without Boilerplate" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "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)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] [[package]] name = "backcall" @@ -36,52 +36,35 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "backports.entry-points-selectable" -version = "1.1.0" -description = "Compatibility shim providing selectable entry points for older implementations" -category = "dev" -optional = false -python-versions = ">=2.7" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"] - [[package]] name = "black" -version = "21.9b0" +version = "22.3.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] -click = ">=7.1.2" +click = ">=8.0.0" mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0,<1" +pathspec = ">=0.9.0" platformdirs = ">=2" -regex = ">=2020.1.8" -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\""}, -] +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -python2 = ["typed-ast (>=1.4.2)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "click" -version = "8.0.3" +version = "8.1.2" description = "Composable command line interface toolkit" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -94,40 +77,20 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -[[package]] -name = "configparser" -version = "4.0.2" -description = "Updated configparser from Python 3.7 for Python 2.6+." -category = "main" -optional = false -python-versions = ">=2.6" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2)", "pytest-flake8", "pytest-black-multipy"] - -[[package]] -name = "contextlib2" -version = "0.6.0.post1" -description = "Backports and enhancements for the contextlib module" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - [[package]] name = "coverage" -version = "6.0.2" +version = "6.3.2" description = "Code coverage measurement for Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] toml = ["tomli"] [[package]] name = "decorator" -version = "5.1.0" +version = "5.1.1" description = "Decorators for Humans" category = "dev" optional = false @@ -135,7 +98,7 @@ python-versions = ">=3.5" [[package]] name = "distlib" -version = "0.3.3" +version = "0.3.4" description = "Distribution utilities" category = "dev" optional = false @@ -151,11 +114,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "filelock" -version = "3.3.1" +version = "3.6.0" description = "A platform independent file lock." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] @@ -176,7 +139,7 @@ pyflakes = ">=2.4.0,<2.5.0" [[package]] name = "flake8-black" -version = "0.2.3" +version = "0.2.5" description = "flake8 plugin to call black as a code style validator" category = "dev" optional = false @@ -189,7 +152,7 @@ toml = "*" [[package]] name = "flake8-bugbear" -version = "21.9.2" +version = "21.11.29" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." category = "dev" optional = false @@ -200,18 +163,18 @@ attrs = ">=19.2.0" flake8 = ">=3.0.0" [package.extras] -dev = ["coverage", "black", "hypothesis", "hypothesmith"] +dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit"] [[package]] name = "flake8-comprehensions" -version = "3.7.0" +version = "3.8.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -flake8 = ">=3.0,<3.2.0 || >3.2.0,<5" +flake8 = ">=3.0,<3.2.0 || >3.2.0" [[package]] name = "flake8-docstrings" @@ -276,16 +239,13 @@ flake8-plugin-utils = ">=1.0,<2.0" [[package]] name = "importlib-metadata" -version = "2.1.1" +version = "2.1.3" description = "Read metadata from Python packages" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] -configparser = {version = ">=3.5", markers = "python_version < \"3\""} -contextlib2 = {version = "*", markers = "python_version < \"3\""} -pathlib2 = {version = "*", markers = "python_version < \"3\""} zipp = ">=0.5" [package.extras] @@ -302,7 +262,7 @@ python-versions = "*" [[package]] name = "ipython" -version = "7.28.0" +version = "7.32.0" description = "IPython: Productive Interactive Computing" category = "dev" optional = false @@ -334,7 +294,7 @@ test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipyk [[package]] name = "jedi" -version = "0.18.0" +version = "0.18.1" description = "An autocompletion tool for Python that can be used for text editors." category = "dev" optional = false @@ -345,7 +305,7 @@ parso = ">=0.8.0,<0.9.0" [package.extras] qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<6.0.0)"] +testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"] [[package]] name = "matplotlib-inline" @@ -366,6 +326,24 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "mypy" +version = "0.942" +description = "Optional static typing for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = ">=1.1.0" +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + [[package]] name = "mypy-extensions" version = "0.4.3" @@ -376,18 +354,18 @@ python-versions = "*" [[package]] name = "packaging" -version = "21.0" +version = "21.3" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "parso" -version = "0.8.2" +version = "0.8.3" description = "A Python Parser" category = "dev" optional = false @@ -397,18 +375,6 @@ python-versions = ">=3.6" qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] testing = ["docopt", "pytest (<6.0.0)"] -[[package]] -name = "pathlib2" -version = "2.3.6" -description = "Object-oriented filesystem paths" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -scandir = {version = "*", markers = "python_version < \"3.5\""} -six = "*" - [[package]] name = "pathspec" version = "0.9.0" @@ -450,11 +416,11 @@ python-versions = "*" [[package]] name = "platformdirs" -version = "2.4.0" +version = "2.5.1" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] @@ -474,7 +440,7 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "prompt-toolkit" -version = "3.0.21" +version = "3.0.29" description = "Library for building powerful interactive command lines in Python" category = "dev" optional = false @@ -493,11 +459,11 @@ python-versions = "*" [[package]] name = "py" -version = "1.10.0" +version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pycodestyle" @@ -531,7 +497,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.10.0" +version = "2.11.2" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false @@ -539,14 +505,14 @@ python-versions = ">=3.5" [[package]] name = "pyparsing" -version = "3.0.0" -description = "Python parsing module" +version = "3.0.8" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.8" [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pytest" @@ -569,17 +535,9 @@ toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] -[[package]] -name = "regex" -version = "2021.10.23" -description = "Alternative regular expression module, to replace re." -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "rstcheck" -version = "3.3.1" +version = "3.5.0" description = "Checks syntax of reStructuredText and code blocks nested within it" category = "dev" optional = false @@ -588,14 +546,6 @@ python-versions = "*" [package.dependencies] docutils = ">=0.7" -[[package]] -name = "scandir" -version = "1.10.0" -description = "scandir, a better directory iterator and faster os.walk()" -category = "main" -optional = false -python-versions = "*" - [[package]] name = "six" version = "1.16.0" @@ -606,7 +556,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "snowballstemmer" -version = "2.1.0" +version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." category = "dev" optional = false @@ -622,15 +572,15 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomli" -version = "1.2.1" +version = "2.0.1" description = "A lil' TOML parser" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "tox" -version = "3.24.4" +version = "3.25.0" description = "tox is a generic virtualenv management and test command line tool" category = "dev" optional = false @@ -648,11 +598,11 @@ virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2, [package.extras] docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] -testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)", "pytest-xdist (>=1.22.2)", "pathlib2 (>=2.3.3)"] +testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)", "psutil (>=5.6.1)", "pathlib2 (>=2.3.3)"] [[package]] name = "traitlets" -version = "5.1.0" +version = "5.1.1" description = "Traitlets Python configuration system" category = "dev" optional = false @@ -663,29 +613,28 @@ test = ["pytest"] [[package]] name = "typing-extensions" -version = "3.10.0.2" -description = "Backported and Experimental Type Hints for Python 3.5+" +version = "4.1.1" +description = "Backported and Experimental Type Hints for Python 3.6+" category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "virtualenv" -version = "20.9.0" +version = "20.14.1" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] -"backports.entry-points-selectable" = ">=1.0.4" distlib = ">=0.3.1,<1" filelock = ">=3.2,<4" platformdirs = ">=2,<3" six = ">=1.9.0,<2" [package.extras] -docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] +docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] [[package]] @@ -704,125 +653,139 @@ category = "main" optional = false python-versions = ">=2.7" -[package.dependencies] -contextlib2 = {version = "*", markers = "python_version < \"3.4\""} - [package.extras] docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["pathlib2", "unittest2", "jaraco.itertools", "func-timeout"] [metadata] lock-version = "1.1" -python-versions = "~2.7 || ^3.5" -content-hash = "5bda3522682ddac475f32fd4de0a08658f91040ba8e32a37192271b2af6abe0c" +python-versions = "^3.5" +content-hash = "980f0772bf3b2936ed86f78bd4c7d993349b14754245c6d557bcc7abc50c8728" [metadata.files] appnope = [ - {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, - {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, - {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, + {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, + {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] backcall = [ {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] -"backports.entry-points-selectable" = [ - {file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"}, - {file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"}, -] black = [ - {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, - {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, + {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, + {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, + {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"}, + {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"}, + {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"}, + {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"}, + {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"}, + {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"}, + {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"}, + {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"}, + {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"}, + {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"}, + {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"}, + {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"}, + {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"}, + {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"}, + {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"}, + {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, + {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, ] click = [ - {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, - {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, + {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, + {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] -configparser = [ - {file = "configparser-4.0.2-py2.py3-none-any.whl", hash = "sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c"}, - {file = "configparser-4.0.2.tar.gz", hash = "sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df"}, -] -contextlib2 = [ - {file = "contextlib2-0.6.0.post1-py2.py3-none-any.whl", hash = "sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b"}, - {file = "contextlib2-0.6.0.post1.tar.gz", hash = "sha256:01f490098c18b19d2bd5bb5dc445b2054d2fa97f09a4280ba2c5f3c394c8162e"}, -] coverage = [ - {file = "coverage-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1549e1d08ce38259de2bc3e9a0d5f3642ff4a8f500ffc1b2df73fd621a6cdfc0"}, - {file = "coverage-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcae10fccb27ca2a5f456bf64d84110a5a74144be3136a5e598f9d9fb48c0caa"}, - {file = "coverage-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:53a294dc53cfb39c74758edaa6305193fb4258a30b1f6af24b360a6c8bd0ffa7"}, - {file = "coverage-6.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8251b37be1f2cd9c0e5ccd9ae0380909c24d2a5ed2162a41fcdbafaf59a85ebd"}, - {file = "coverage-6.0.2-cp310-cp310-win32.whl", hash = "sha256:db42baa892cba723326284490283a68d4de516bfb5aaba369b4e3b2787a778b7"}, - {file = "coverage-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:bbffde2a68398682623d9dd8c0ca3f46fda074709b26fcf08ae7a4c431a6ab2d"}, - {file = "coverage-6.0.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:60e51a3dd55540bec686d7fff61b05048ca31e804c1f32cbb44533e6372d9cc3"}, - {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a6a9409223a27d5ef3cca57dd7cd4dfcb64aadf2fad5c3b787830ac9223e01a"}, - {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4b34ae4f51bbfa5f96b758b55a163d502be3dcb24f505d0227858c2b3f94f5b9"}, - {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3bbda1b550e70fa6ac40533d3f23acd4f4e9cb4e6e77251ce77fdf41b3309fb2"}, - {file = "coverage-6.0.2-cp36-cp36m-win32.whl", hash = "sha256:4e28d2a195c533b58fc94a12826f4431726d8eb029ac21d874345f943530c122"}, - {file = "coverage-6.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a82d79586a0a4f5fd1cf153e647464ced402938fbccb3ffc358c7babd4da1dd9"}, - {file = "coverage-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3be1206dc09fb6298de3fce70593e27436862331a85daee36270b6d0e1c251c4"}, - {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9cd3828bbe1a40070c11fe16a51df733fd2f0cb0d745fb83b7b5c1f05967df7"}, - {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d036dc1ed8e1388e995833c62325df3f996675779541f682677efc6af71e96cc"}, - {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:04560539c19ec26995ecfb3d9307ff154fbb9a172cb57e3b3cfc4ced673103d1"}, - {file = "coverage-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:e4fb7ced4d9dec77d6cf533acfbf8e1415fe799430366affb18d69ee8a3c6330"}, - {file = "coverage-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:77b1da5767ed2f44611bc9bc019bc93c03fa495728ec389759b6e9e5039ac6b1"}, - {file = "coverage-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61b598cbdbaae22d9e34e3f675997194342f866bb1d781da5d0be54783dce1ff"}, - {file = "coverage-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36e9040a43d2017f2787b28d365a4bb33fcd792c7ff46a047a04094dc0e2a30d"}, - {file = "coverage-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9f1627e162e3864a596486774876415a7410021f4b67fd2d9efdf93ade681afc"}, - {file = "coverage-6.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e7a0b42db2a47ecb488cde14e0f6c7679a2c5a9f44814393b162ff6397fcdfbb"}, - {file = "coverage-6.0.2-cp38-cp38-win32.whl", hash = "sha256:a1b73c7c4d2a42b9d37dd43199c5711d91424ff3c6c22681bc132db4a4afec6f"}, - {file = "coverage-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:1db67c497688fd4ba85b373b37cc52c50d437fd7267520ecd77bddbd89ea22c9"}, - {file = "coverage-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f2f184bf38e74f152eed7f87e345b51f3ab0b703842f447c22efe35e59942c24"}, - {file = "coverage-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1cf1deb3d5544bd942356364a2fdc8959bad2b6cf6eb17f47d301ea34ae822"}, - {file = "coverage-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ad9b8c1206ae41d46ec7380b78ba735ebb77758a650643e841dd3894966c31d0"}, - {file = "coverage-6.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:381d773d896cc7f8ba4ff3b92dee4ed740fb88dfe33b6e42efc5e8ab6dfa1cfe"}, - {file = "coverage-6.0.2-cp39-cp39-win32.whl", hash = "sha256:424c44f65e8be58b54e2b0bd1515e434b940679624b1b72726147cfc6a9fc7ce"}, - {file = "coverage-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:abbff240f77347d17306d3201e14431519bf64495648ca5a49571f988f88dee9"}, - {file = "coverage-6.0.2-pp36-none-any.whl", hash = "sha256:7092eab374346121805fb637572483270324407bf150c30a3b161fc0c4ca5164"}, - {file = "coverage-6.0.2-pp37-none-any.whl", hash = "sha256:30922626ce6f7a5a30bdba984ad21021529d3d05a68b4f71ea3b16bda35b8895"}, - {file = "coverage-6.0.2.tar.gz", hash = "sha256:6807947a09510dc31fa86f43595bf3a14017cd60bf633cc746d52141bfa6b149"}, + {file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"}, + {file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"}, + {file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"}, + {file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"}, + {file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"}, + {file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"}, + {file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"}, + {file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"}, + {file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"}, + {file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"}, + {file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"}, + {file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"}, + {file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"}, + {file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"}, + {file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"}, + {file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"}, + {file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"}, + {file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"}, + {file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"}, + {file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"}, + {file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"}, + {file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"}, + {file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"}, + {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, + {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, ] decorator = [ - {file = "decorator-5.1.0-py3-none-any.whl", hash = "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374"}, - {file = "decorator-5.1.0.tar.gz", hash = "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7"}, + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] distlib = [ - {file = "distlib-0.3.3-py2.py3-none-any.whl", hash = "sha256:c8b54e8454e5bf6237cc84c20e8264c3e991e824ef27e8f1e81049867d861e31"}, - {file = "distlib-0.3.3.zip", hash = "sha256:d982d0751ff6eaaab5e2ec8e691d949ee80eddf01a62eaa96ddb11531fe16b05"}, + {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, + {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, ] docutils = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] filelock = [ - {file = "filelock-3.3.1-py3-none-any.whl", hash = "sha256:2b5eb3589e7fdda14599e7eb1a50e09b4cc14f34ed98b8ba56d33bfaafcbef2f"}, - {file = "filelock-3.3.1.tar.gz", hash = "sha256:34a9f35f95c441e7b38209775d6e0337f9a3759f3565f6c5798f19618527c76f"}, + {file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"}, + {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"}, ] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, ] flake8-black = [ - {file = "flake8-black-0.2.3.tar.gz", hash = "sha256:c199844bc1b559d91195ebe8620216f21ed67f2cc1ff6884294c91a0d2492684"}, - {file = "flake8_black-0.2.3-py3-none-any.whl", hash = "sha256:cc080ba5b3773b69ba102b6617a00cc4ecbad8914109690cfda4d565ea435d96"}, + {file = "flake8-black-0.2.5.tar.gz", hash = "sha256:fb6372cc90da129eec492989485a4f99d976f41d4072536470c18e0da0164724"}, + {file = "flake8_black-0.2.5-py3-none-any.whl", hash = "sha256:022744ef1513f9a0b748c65ae2a81024d71b992c88f48212187a3fdbb4988943"}, ] flake8-bugbear = [ - {file = "flake8-bugbear-21.9.2.tar.gz", hash = "sha256:db9a09893a6c649a197f5350755100bb1dd84f110e60cf532fdfa07e41808ab2"}, - {file = "flake8_bugbear-21.9.2-py36.py37.py38-none-any.whl", hash = "sha256:4f7eaa6f05b7d7ea4cbbde93f7bcdc5438e79320fa1ec420d860c181af38b769"}, + {file = "flake8-bugbear-21.11.29.tar.gz", hash = "sha256:8b04cb2fafc6a78e1a9d873bd3988e4282f7959bb6b0d7c1ae648ec09b937a7b"}, + {file = "flake8_bugbear-21.11.29-py36.py37.py38-none-any.whl", hash = "sha256:179e41ddae5de5e3c20d1f61736feeb234e70958fbb56ab3c28a67739c8e9a82"}, ] flake8-comprehensions = [ - {file = "flake8-comprehensions-3.7.0.tar.gz", hash = "sha256:6b3218b2dde8ac5959c6476cde8f41a79e823c22feb656be2710cd2a3232cef9"}, - {file = "flake8_comprehensions-3.7.0-py3-none-any.whl", hash = "sha256:a5d7aea6315bbbd6fbcb2b4e80bff6a54d1600155e26236e555d0c6fe1d62522"}, + {file = "flake8-comprehensions-3.8.0.tar.gz", hash = "sha256:8e108707637b1d13734f38e03435984f6b7854fa6b5a4e34f93e69534be8e521"}, + {file = "flake8_comprehensions-3.8.0-py3-none-any.whl", hash = "sha256:9406314803abe1193c064544ab14fdc43c58424c0882f6ff8a581eb73fc9bb58"}, ] flake8-docstrings = [ {file = "flake8-docstrings-1.6.0.tar.gz", hash = "sha256:9fe7c6a306064af8e62a055c2f61e9eb1da55f84bb39caef2b84ce53708ac34b"}, @@ -848,20 +811,20 @@ flake8-return = [ {file = "flake8_return-1.1.3-py3-none-any.whl", hash = "sha256:4a266191f7ed69aa26b835ec90c5a5522fa8f79f5cf6363a877ac499f8eb418b"}, ] importlib-metadata = [ - {file = "importlib_metadata-2.1.1-py2.py3-none-any.whl", hash = "sha256:c2d6341ff566f609e89a2acb2db190e5e1d23d5409d6cc8d2fe34d72443876d4"}, - {file = "importlib_metadata-2.1.1.tar.gz", hash = "sha256:b8de9eff2b35fb037368f28a7df1df4e6436f578fa74423505b6c6a778d5b5dd"}, + {file = "importlib_metadata-2.1.3-py2.py3-none-any.whl", hash = "sha256:52e65a0856f9ba7ea8f2c4ced253fb6c88d1a8c352cb1e916cff4eb17d5a693d"}, + {file = "importlib_metadata-2.1.3.tar.gz", hash = "sha256:02a9f62b02e9b1cc43871809ef99947e8f5d94771392d666ada2cafc4cd09d4f"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] ipython = [ - {file = "ipython-7.28.0-py3-none-any.whl", hash = "sha256:f16148f9163e1e526f1008d7c8d966d9c15600ca20d1a754287cf96d00ba6f1d"}, - {file = "ipython-7.28.0.tar.gz", hash = "sha256:2097be5c814d1b974aea57673176a924c4c8c9583890e7a5f082f547b9975b11"}, + {file = "ipython-7.32.0-py3-none-any.whl", hash = "sha256:86df2cf291c6c70b5be6a7b608650420e89180c8ec74f376a34e2dc15c3400e7"}, + {file = "ipython-7.32.0.tar.gz", hash = "sha256:468abefc45c15419e3c8e8c0a6a5c115b2127bafa34d7c641b1d443658793909"}, ] jedi = [ - {file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"}, - {file = "jedi-0.18.0.tar.gz", hash = "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707"}, + {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, + {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, ] matplotlib-inline = [ {file = "matplotlib-inline-0.1.3.tar.gz", hash = "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee"}, @@ -871,21 +834,42 @@ mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +mypy = [ + {file = "mypy-0.942-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d"}, + {file = "mypy-0.942-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46"}, + {file = "mypy-0.942-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0"}, + {file = "mypy-0.942-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee"}, + {file = "mypy-0.942-cp310-cp310-win_amd64.whl", hash = "sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17"}, + {file = "mypy-0.942-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904"}, + {file = "mypy-0.942-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5"}, + {file = "mypy-0.942-cp36-cp36m-win_amd64.whl", hash = "sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c"}, + {file = "mypy-0.942-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58"}, + {file = "mypy-0.942-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6"}, + {file = "mypy-0.942-cp37-cp37m-win_amd64.whl", hash = "sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e"}, + {file = "mypy-0.942-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67"}, + {file = "mypy-0.942-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c"}, + {file = "mypy-0.942-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b"}, + {file = "mypy-0.942-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3"}, + {file = "mypy-0.942-cp38-cp38-win_amd64.whl", hash = "sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8"}, + {file = "mypy-0.942-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca"}, + {file = "mypy-0.942-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16"}, + {file = "mypy-0.942-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6"}, + {file = "mypy-0.942-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322"}, + {file = "mypy-0.942-cp39-cp39-win_amd64.whl", hash = "sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534"}, + {file = "mypy-0.942-py3-none-any.whl", hash = "sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db"}, + {file = "mypy-0.942.tar.gz", hash = "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2"}, +] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ - {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, - {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] parso = [ - {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"}, - {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"}, -] -pathlib2 = [ - {file = "pathlib2-2.3.6-py2.py3-none-any.whl", hash = "sha256:3a130b266b3a36134dcc79c17b3c7ac9634f083825ca6ea9d8f557ee6195c9c8"}, - {file = "pathlib2-2.3.6.tar.gz", hash = "sha256:7d8bcb5555003cdf4a8d2872c538faa3a0f5d20630cb360e518ca3b981795e5f"}, + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, ] pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, @@ -904,24 +888,24 @@ pickleshare = [ {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, ] platformdirs = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, + {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, + {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] prompt-toolkit = [ - {file = "prompt_toolkit-3.0.21-py3-none-any.whl", hash = "sha256:62b3d3ea5a3ccee94dc1aac018279cf64866a76837156ebe159b981c42dd20a8"}, - {file = "prompt_toolkit-3.0.21.tar.gz", hash = "sha256:27f13ff4e4850fe8f860b77414c7880f67c6158076a7b099062cc8570f1562e5"}, + {file = "prompt_toolkit-3.0.29-py3-none-any.whl", hash = "sha256:62291dad495e665fca0bda814e342c69952086afb0f4094d0893d357e5c78752"}, + {file = "prompt_toolkit-3.0.29.tar.gz", hash = "sha256:bd640f60e8cecd74f0dc249713d433ace2ddc62b65ee07f96d358e0b152b6ea7"}, ] ptyprocess = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, ] py = [ - {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, - {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pycodestyle = [ {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, @@ -936,103 +920,52 @@ pyflakes = [ {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, ] pygments = [ - {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, - {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, + {file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"}, + {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"}, ] pyparsing = [ - {file = "pyparsing-3.0.0-py3-none-any.whl", hash = "sha256:d487599e9fb0dc36bee6b5c183c6fc5bd372ce667736f3d430ab7d842a54a35a"}, - {file = "pyparsing-3.0.0.tar.gz", hash = "sha256:001cad8d467e7a9248ef9fd513f5c0d39afcbcb9a43684101853bd0ab962e479"}, + {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, + {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, ] pytest = [ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] -regex = [ - {file = "regex-2021.10.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:45b65d6a275a478ac2cbd7fdbf7cc93c1982d613de4574b56fd6972ceadb8395"}, - {file = "regex-2021.10.23-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74d071dbe4b53c602edd87a7476ab23015a991374ddb228d941929ad7c8c922e"}, - {file = "regex-2021.10.23-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34d870f9f27f2161709054d73646fc9aca49480617a65533fc2b4611c518e455"}, - {file = "regex-2021.10.23-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fb698037c35109d3c2e30f2beb499e5ebae6e4bb8ff2e60c50b9a805a716f79"}, - {file = "regex-2021.10.23-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb46b542133999580ffb691baf67410306833ee1e4f58ed06b6a7aaf4e046952"}, - {file = "regex-2021.10.23-cp310-cp310-win32.whl", hash = "sha256:5e9c9e0ce92f27cef79e28e877c6b6988c48b16942258f3bc55d39b5f911df4f"}, - {file = "regex-2021.10.23-cp310-cp310-win_amd64.whl", hash = "sha256:ab7c5684ff3538b67df3f93d66bd3369b749087871ae3786e70ef39e601345b0"}, - {file = "regex-2021.10.23-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de557502c3bec8e634246588a94e82f1ee1b9dfcfdc453267c4fb652ff531570"}, - {file = "regex-2021.10.23-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee684f139c91e69fe09b8e83d18b4d63bf87d9440c1eb2eeb52ee851883b1b29"}, - {file = "regex-2021.10.23-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5095a411c8479e715784a0c9236568ae72509450ee2226b649083730f3fadfc6"}, - {file = "regex-2021.10.23-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b568809dca44cb75c8ebb260844ea98252c8c88396f9d203f5094e50a70355f"}, - {file = "regex-2021.10.23-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eb672217f7bd640411cfc69756ce721d00ae600814708d35c930930f18e8029f"}, - {file = "regex-2021.10.23-cp36-cp36m-win32.whl", hash = "sha256:a7a986c45d1099a5de766a15de7bee3840b1e0e1a344430926af08e5297cf666"}, - {file = "regex-2021.10.23-cp36-cp36m-win_amd64.whl", hash = "sha256:6d7722136c6ed75caf84e1788df36397efdc5dbadab95e59c2bba82d4d808a4c"}, - {file = "regex-2021.10.23-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f665677e46c5a4d288ece12fdedf4f4204a422bb28ff05f0e6b08b7447796d1"}, - {file = "regex-2021.10.23-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:450dc27483548214314640c89a0f275dbc557968ed088da40bde7ef8fb52829e"}, - {file = "regex-2021.10.23-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:129472cd06062fb13e7b4670a102951a3e655e9b91634432cfbdb7810af9d710"}, - {file = "regex-2021.10.23-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a940ca7e7189d23da2bfbb38973832813eab6bd83f3bf89a977668c2f813deae"}, - {file = "regex-2021.10.23-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:530fc2bbb3dc1ebb17f70f7b234f90a1dd43b1b489ea38cea7be95fb21cdb5c7"}, - {file = "regex-2021.10.23-cp37-cp37m-win32.whl", hash = "sha256:ded0c4a3eee56b57fcb2315e40812b173cafe79d2f992d50015f4387445737fa"}, - {file = "regex-2021.10.23-cp37-cp37m-win_amd64.whl", hash = "sha256:391703a2abf8013d95bae39145d26b4e21531ab82e22f26cd3a181ee2644c234"}, - {file = "regex-2021.10.23-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be04739a27be55631069b348dda0c81d8ea9822b5da10b8019b789e42d1fe452"}, - {file = "regex-2021.10.23-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13ec99df95003f56edcd307db44f06fbeb708c4ccdcf940478067dd62353181e"}, - {file = "regex-2021.10.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d1cdcda6bd16268316d5db1038965acf948f2a6f43acc2e0b1641ceab443623"}, - {file = "regex-2021.10.23-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c186691a7995ef1db61205e00545bf161fb7b59cdb8c1201c89b333141c438a"}, - {file = "regex-2021.10.23-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b20f544cbbeffe171911f6ce90388ad36fe3fad26b7c7a35d4762817e9ea69c"}, - {file = "regex-2021.10.23-cp38-cp38-win32.whl", hash = "sha256:c0938ddd60cc04e8f1faf7a14a166ac939aac703745bfcd8e8f20322a7373019"}, - {file = "regex-2021.10.23-cp38-cp38-win_amd64.whl", hash = "sha256:56f0c81c44638dfd0e2367df1a331b4ddf2e771366c4b9c5d9a473de75e3e1c7"}, - {file = "regex-2021.10.23-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80bb5d2e92b2258188e7dcae5b188c7bf868eafdf800ea6edd0fbfc029984a88"}, - {file = "regex-2021.10.23-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1dae12321b31059a1a72aaa0e6ba30156fe7e633355e445451e4021b8e122b6"}, - {file = "regex-2021.10.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1f2b59c28afc53973d22e7bc18428721ee8ca6079becf1b36571c42627321c65"}, - {file = "regex-2021.10.23-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d134757a37d8640f3c0abb41f5e68b7cf66c644f54ef1cb0573b7ea1c63e1509"}, - {file = "regex-2021.10.23-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0dcc0e71118be8c69252c207630faf13ca5e1b8583d57012aae191e7d6d28b84"}, - {file = "regex-2021.10.23-cp39-cp39-win32.whl", hash = "sha256:a30513828180264294953cecd942202dfda64e85195ae36c265daf4052af0464"}, - {file = "regex-2021.10.23-cp39-cp39-win_amd64.whl", hash = "sha256:0f7552429dd39f70057ac5d0e897e5bfe211629652399a21671e53f2a9693a4e"}, - {file = "regex-2021.10.23.tar.gz", hash = "sha256:f3f9a91d3cc5e5b0ddf1043c0ae5fa4852f18a1c0050318baf5fc7930ecc1f9c"}, -] rstcheck = [ - {file = "rstcheck-3.3.1.tar.gz", hash = "sha256:92c4f79256a54270e0402ba16a2f92d0b3c15c8f4410cb9c57127067c215741f"}, -] -scandir = [ - {file = "scandir-1.10.0-cp27-cp27m-win32.whl", hash = "sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188"}, - {file = "scandir-1.10.0-cp27-cp27m-win_amd64.whl", hash = "sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac"}, - {file = "scandir-1.10.0-cp34-cp34m-win32.whl", hash = "sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f"}, - {file = "scandir-1.10.0-cp34-cp34m-win_amd64.whl", hash = "sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e"}, - {file = "scandir-1.10.0-cp35-cp35m-win32.whl", hash = "sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f"}, - {file = "scandir-1.10.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32"}, - {file = "scandir-1.10.0-cp36-cp36m-win32.whl", hash = "sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022"}, - {file = "scandir-1.10.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4"}, - {file = "scandir-1.10.0-cp37-cp37m-win32.whl", hash = "sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173"}, - {file = "scandir-1.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d"}, - {file = "scandir-1.10.0.tar.gz", hash = "sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae"}, + {file = "rstcheck-3.5.0-py3-none-any.whl", hash = "sha256:30c36768c4bd617a85ab93c31facaf410582e53803fde624845eb00c1430070c"}, + {file = "rstcheck-3.5.0.tar.gz", hash = "sha256:d4b035300b7d898403544f38c3a4980171ce85f487d25e188347bbafb6ee58c0"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] snowballstemmer = [ - {file = "snowballstemmer-2.1.0-py2.py3-none-any.whl", hash = "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2"}, - {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tomli = [ - {file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"}, - {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] tox = [ - {file = "tox-3.24.4-py2.py3-none-any.whl", hash = "sha256:5e274227a53dc9ef856767c21867377ba395992549f02ce55eb549f9fb9a8d10"}, - {file = "tox-3.24.4.tar.gz", hash = "sha256:c30b57fa2477f1fb7c36aa1d83292d5c2336cd0018119e1b1c17340e2c2708ca"}, + {file = "tox-3.25.0-py2.py3-none-any.whl", hash = "sha256:0805727eb4d6b049de304977dfc9ce315a1938e6619c3ab9f38682bb04662a5a"}, + {file = "tox-3.25.0.tar.gz", hash = "sha256:37888f3092aa4e9f835fc8cc6dadbaaa0782651c41ef359e3a5743fcb0308160"}, ] traitlets = [ - {file = "traitlets-5.1.0-py3-none-any.whl", hash = "sha256:03f172516916220b58c9f19d7f854734136dd9528103d04e9bf139a92c9f54c4"}, - {file = "traitlets-5.1.0.tar.gz", hash = "sha256:bd382d7ea181fbbcce157c133db9a829ce06edffe097bcf3ab945b435452b46d"}, + {file = "traitlets-5.1.1-py3-none-any.whl", hash = "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033"}, + {file = "traitlets-5.1.1.tar.gz", hash = "sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, + {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, + {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, ] virtualenv = [ - {file = "virtualenv-20.9.0-py2.py3-none-any.whl", hash = "sha256:1d145deec2da86b29026be49c775cc5a9aab434f85f7efef98307fb3965165de"}, - {file = "virtualenv-20.9.0.tar.gz", hash = "sha256:bb55ace18de14593947354e5e6cd1be75fb32c3329651da62e92bf5d0aab7213"}, + {file = "virtualenv-20.14.1-py2.py3-none-any.whl", hash = "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a"}, + {file = "virtualenv-20.14.1.tar.gz", hash = "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, diff --git a/pyproject.toml b/pyproject.toml index 6d0b461..42ff47b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "flatten-dict" -version = "0.4.3" +version = "0.5.3" description = "A flexible utility for flattening and unflattening dict-like objects in Python." authors = ["Ian Lin "] license = "MIT" @@ -12,14 +12,14 @@ classifiers = [ ] [tool.poetry.dependencies] -python = "~2.7 || ^3.5" +python = "^3.5" six = "^1.12" -pathlib2 = { version = "^2.3", python = "<3.4" } importlib-metadata = {version = "*", python = "<3.8"} [tool.poetry.dev-dependencies] pytest = { version = "^6.0", python = "^3.8" } flake8 = { version = "^4.0", python = "^3.8" } +mypy = { version = "^0.942", python = "^3.8" } pep8-naming = { version = "^0.12.0", python = "^3.8"} flake8-import-order = { version = "^0.18.1", python = "^3.8"} flake8-bugbear = { version = "^21.4.0", python = "^3.8"} @@ -30,7 +30,7 @@ flake8-return = { version = "^1.1.2", python = "^3.8"} flake8-black = { version = "^0.2.1", python = "^3.8"} tox = { version = "^3.19", python = "^3.8" } coverage = { version = "^6.0", python = "^3.8" } -black = { version = "= 21.9b0", python = "^3.8" } +black = { version = "= 22.3.0", python = "^3.8" } rstcheck = { version = "^3.3.1", python = "^3.8" } docutils = { version = "^0.17", python = "^3.8" } ipython = { version = "^7.26.0", python = "^3.8" } diff --git a/setup.cfg b/setup.cfg index 91552b9..abcd3d8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -85,3 +85,12 @@ max-line-length = 99 import-order-style = pep8 application-import-names = flatten_dict docstring-convention = numpy + + +[mypy] +warn_return_any = True +warn_unused_configs = True +disallow_untyped_defs = True + +[mypy-pytest,six,importlib_metadata] +ignore_missing_imports = True diff --git a/src/flatten_dict/__init__.py b/src/flatten_dict/__init__.py index bfcfb93..0f2564e 100644 --- a/src/flatten_dict/__init__.py +++ b/src/flatten_dict/__init__.py @@ -1,12 +1,25 @@ -from .flatten_dict import flatten, unflatten # noqa: F401 +import sys +from .flatten_dict import ( + flatten, + unflatten, + TReducerCallable, + TSplitterCallable, +) # noqa: F401 -__all__ = ["flatten", "unflatten", "splitter"] -try: +__all__ = [ + "flatten", + "unflatten", + "splitter", + "TReducerCallable", + "TSplitterCallable", +] + +if sys.version_info >= (3, 8): # for Python >= 3.8 from importlib.metadata import version -except ImportError: +else: # for Python < 3.8, the package importlib-metadata will be installed from importlib_metadata import version diff --git a/src/flatten_dict/flatten_dict.py b/src/flatten_dict/flatten_dict.py index e392fc5..2f125f0 100644 --- a/src/flatten_dict/flatten_dict.py +++ b/src/flatten_dict/flatten_dict.py @@ -1,24 +1,64 @@ import inspect +import sys +from collections.abc import Mapping +from typing import ( + cast, + Any, + Callable, + Dict, + Hashable, + Iterable, + Optional, + Sequence, + Union, + Tuple, + TypeVar, + overload, +) +import typing + +if sys.version_info < (3, 8): + from typing_extensions import Literal +else: + from typing import Literal -try: - from collections.abc import Mapping -except ImportError: - from collections import Mapping import six from .reducers import tuple_reducer, path_reducer, dot_reducer, underscore_reducer from .splitters import tuple_splitter, path_splitter, dot_splitter, underscore_splitter +TKeyIn = TypeVar("TKeyIn", bound=Hashable) +TKeyIn2 = TypeVar("TKeyIn2", bound=Hashable) +TKeyOut = TypeVar("TKeyOut", bound=Hashable) + +TReducerCallable2Args = Callable[ + [Optional[Union[TKeyIn, TKeyOut]], Union[TKeyIn, int]], TKeyOut +] + +TReducerCallable3Args = Callable[ + [ + Optional[Union[TKeyIn, TKeyOut]], + Union[TKeyIn, int], + Union[typing.Mapping[TKeyIn, Any], Iterable[Any]], + ], + TKeyOut, +] + + +TReducerCallable = Union[TReducerCallable2Args, TReducerCallable3Args] + +TSplitterCallable = Callable[[TKeyIn], Tuple[TKeyOut, ...]] -REDUCER_DICT = { + +REDUCER_DICT: Dict[str, TReducerCallable2Args] = { "tuple": tuple_reducer, "path": path_reducer, "dot": dot_reducer, "underscore": underscore_reducer, } -SPLITTER_DICT = { +SPLITTER_DICT: Dict[str, TSplitterCallable] = { "tuple": tuple_splitter, "path": path_splitter, "dot": dot_splitter, @@ -26,14 +66,118 @@ } +@overload def flatten( - d, - reducer="tuple", - inverse=False, - max_flatten_depth=None, - enumerate_types=(), - keep_empty_types=(), -): + d: typing.Mapping[TKeyIn, Any], + reducer: Union[ + TReducerCallable2Args[TKeyIn, TKeyOut], TReducerCallable3Args[TKeyIn, TKeyOut] + ], + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Dict[TKeyOut, Any]: + pass + + +@overload +def flatten( + d: typing.Mapping[TKeyIn, Any], + reducer: Literal["tuple"] = "tuple", + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Dict[Tuple[Any, ...], Any]: + pass + + +@overload +def flatten( + d: typing.Mapping[TKeyIn, Any], + reducer: Literal["dot", "path", "underscore"], + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Dict[Union[TKeyIn, str], Any]: + pass + + +@overload +def flatten( + d: typing.Mapping[TKeyIn, Any], + reducer: str = "tuple", + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Union[Dict[Tuple[Any, ...], Any], Dict[Union[TKeyIn, str], Any]]: + pass + + +@overload +def flatten( + d: Sequence[Any], + reducer: Union[ + TReducerCallable2Args[TKeyIn, TKeyOut], TReducerCallable3Args[TKeyIn, TKeyOut] + ], + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Dict[TKeyOut, Any]: + pass + + +@overload +def flatten( + d: Sequence[Any], + reducer: Literal["tuple"] = "tuple", + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Dict[Tuple[Any, ...], Any]: + pass + + +@overload +def flatten( + d: Sequence[Any], + reducer: Literal["dot", "path", "underscore"], + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Dict[Union[int, str], Any]: + pass + + +@overload +def flatten( + d: Sequence[Any], + reducer: str = "tuple", + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Union[Dict[Tuple[Any, ...], Any], Dict[Union[int, str], Any]]: + pass + + +def flatten( + d: Any, + reducer: Union[ + str, + TReducerCallable2Args[TKeyIn, TKeyOut], + TReducerCallable3Args[TKeyIn, TKeyOut], + ] = "tuple", + inverse: bool = False, + max_flatten_depth: Optional[int] = None, + enumerate_types: Tuple[type, ...] = (), + keep_empty_types: Tuple[type, ...] = (), +) -> Any: """Flatten `Mapping` object. Parameters @@ -81,27 +225,34 @@ def flatten( if max_flatten_depth is not None and max_flatten_depth < 1: raise ValueError("max_flatten_depth should not be less than 1.") - if isinstance(reducer, str): - reducer = REDUCER_DICT[reducer] - try: - # Python 3 - reducer_accepts_parent_obj = len(inspect.signature(reducer).parameters) == 3 - except AttributeError: - # Python 2 - reducer_accepts_parent_obj = len(inspect.getargspec(reducer)[0]) == 3 + reducer = REDUCER_DICT[reducer] if isinstance(reducer, str) else reducer + _reducer2: Optional[TReducerCallable2Args[TKeyIn, TKeyOut]] = None + _reducer3: Optional[TReducerCallable3Args[TKeyIn, TKeyOut]] = None + if len(inspect.signature(reducer).parameters) == 3: + _reducer3 = cast(TReducerCallable3Args[TKeyIn, TKeyOut], reducer) + else: + _reducer2 = cast(TReducerCallable2Args[TKeyIn, TKeyOut], reducer) + flat_dict = {} - def _flatten(_d, depth, parent=None): - key_value_iterable = ( - enumerate(_d) if isinstance(_d, enumerate_types) else six.viewitems(_d) + def _flatten( + _d: Union[ + typing.Mapping[TKeyIn, Any], Any + ], # either mapping or one of enumerate_types + depth: int, + parent: TKeyOut = None, + ) -> bool: + key_value_iterable: Iterable[Tuple[Union[int, TKeyIn], Any]] = ( + enumerate(_d) if isinstance(_d, enumerate_types) else _d.items() ) has_item = False for key, value in key_value_iterable: has_item = True - if reducer_accepts_parent_obj: - flat_key = reducer(parent, key, _d) - else: - flat_key = reducer(parent, key) + if _reducer3 is not None: + flat_key = _reducer3(parent, key, _d) + elif _reducer2 is not None: + flat_key = _reducer2(parent, key) + if isinstance(value, flattenable_types) and ( max_flatten_depth is None or depth < max_flatten_depth ): @@ -125,7 +276,7 @@ def _flatten(_d, depth, parent=None): return flat_dict -def nested_set_dict(d, keys, value): +def nested_set_dict(d: Dict[TKeyIn, Any], keys: Sequence[TKeyIn], value: Any) -> None: """Set a value to a sequence of nested keys. Parameters @@ -145,7 +296,43 @@ def nested_set_dict(d, keys, value): nested_set_dict(d, keys[1:], value) -def unflatten(d, splitter="tuple", inverse=False): +@overload +def unflatten( + d: typing.Mapping[str, Any], + splitter: Literal["dot", "underscore", "path"], + inverse: bool = False, +) -> Dict[str, Any]: + pass + + +@overload +def unflatten( + d: typing.Mapping[Tuple[TKeyIn, ...], Any], + splitter: Literal["tuple"] = "tuple", + inverse: bool = False, +) -> Dict[TKeyIn, Any]: + pass + + +@overload +def unflatten( + d: Union[typing.Mapping[str, Any], typing.Mapping[Tuple[TKeyIn, ...], Any]], + splitter: str = "tuple", + inverse: bool = False, +) -> Union[Dict[str, Any], Dict[TKeyIn, Any]]: + pass + + +@overload +def unflatten( + d: typing.Mapping[TKeyIn, Any], + splitter: Callable[[TKeyIn], Tuple[TKeyOut, ...]], + inverse: bool = False, +) -> Dict[TKeyOut, Any]: + pass + + +def unflatten(d: Any, splitter: Any = "tuple", inverse: bool = False) -> Dict[Any, Any]: """Unflatten dict-like object. Parameters @@ -169,7 +356,7 @@ def unflatten(d, splitter="tuple", inverse=False): if isinstance(splitter, str): splitter = SPLITTER_DICT[splitter] - unflattened_dict = {} + unflattened_dict: Dict[Any, Any] = {} for flat_key, value in six.viewitems(d): if inverse: flat_key, value = value, flat_key diff --git a/src/flatten_dict/py.typed b/src/flatten_dict/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/src/flatten_dict/reducers.py b/src/flatten_dict/reducers.py index 1bcd068..fe0644e 100644 --- a/src/flatten_dict/reducers.py +++ b/src/flatten_dict/reducers.py @@ -1,34 +1,45 @@ -def tuple_reducer(k1, k2): +from typing import Callable, Tuple, TypeVar, Optional, Union + +T = TypeVar("T") + + +def tuple_reducer(k1: Optional[Tuple[T, ...]], k2: T) -> Tuple[T, ...]: if k1 is None: return (k2,) else: return k1 + (k2,) -def path_reducer(k1, k2): +def path_reducer(k1: Optional[str], k2: Union[str, int]) -> str: import os.path if k1 is None: - return k2 + return str(k2) else: - return os.path.join(k1, k2) + return os.path.join(k1, str(k2)) -def dot_reducer(k1, k2): +def dot_reducer( + k1: Optional[Union[T, str, int]], k2: Union[T, int] +) -> Union[T, str, int]: if k1 is None: return k2 else: return "{}.{}".format(k1, k2) -def underscore_reducer(k1, k2): +def underscore_reducer( + k1: Optional[Union[T, str, int]], k2: Union[T, int] +) -> Union[T, str, int]: if k1 is None: return k2 else: return "{}_{}".format(k1, k2) -def make_reducer(delimiter): +def make_reducer( + delimiter: str, +) -> Callable[[Union[T, str, int, None], Union[T, str, int]], Union[T, str, int]]: """Create a reducer with a custom delimiter. Parameters @@ -42,7 +53,9 @@ def make_reducer(delimiter): Callable that can be passed to `flatten()`'s `reducer` argument. """ - def f(k1, k2): + def f( + k1: Optional[Union[T, str, int]], k2: Union[T, str, int] + ) -> Union[T, str, int]: if k1 is None: return k2 else: diff --git a/src/flatten_dict/splitters.py b/src/flatten_dict/splitters.py index 94a81b4..c2e4fe4 100644 --- a/src/flatten_dict/splitters.py +++ b/src/flatten_dict/splitters.py @@ -1,27 +1,30 @@ -def tuple_splitter(flat_key): +from typing import Tuple, Callable, TypeVar, Hashable + +THashable = TypeVar("THashable", bound=Hashable) + + +def tuple_splitter(flat_key: Tuple[THashable, ...]) -> Tuple[THashable, ...]: return flat_key -def path_splitter(flat_key): - try: - from pathlib import PurePath - except ImportError: - from pathlib2 import PurePath +def path_splitter(flat_key: str) -> Tuple[str, ...]: + from pathlib import PurePath + keys = PurePath(flat_key).parts return keys -def dot_splitter(flat_key): +def dot_splitter(flat_key: str) -> Tuple[str, ...]: keys = tuple(flat_key.split(".")) return keys -def underscore_splitter(flat_key): +def underscore_splitter(flat_key: str) -> Tuple[str, ...]: keys = tuple(flat_key.split("_")) return keys -def make_splitter(delimiter): +def make_splitter(delimiter: str) -> Callable[[str], Tuple[str, ...]]: """Create a reducer with a custom delimiter. Parameters @@ -35,7 +38,7 @@ def make_splitter(delimiter): Callable that can be passed to ``unflatten``'s ``splitter`` argument. """ - def f(flat_key): + def f(flat_key: str) -> Tuple[str, ...]: keys = tuple(flat_key.split(delimiter)) return keys diff --git a/src/flatten_dict/tests/flatten_dict_test.py b/src/flatten_dict/tests/flatten_dict_test.py index 581bc11..514440a 100644 --- a/src/flatten_dict/tests/flatten_dict_test.py +++ b/src/flatten_dict/tests/flatten_dict_test.py @@ -3,11 +3,31 @@ import os.path import json from types import GeneratorType +import sys +from typing import ( + Any, + Callable, + Dict, + Iterable, + Iterator, + List, + Mapping, + Optional, + Sequence, + Tuple, + TypeVar, + Union, +) + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal -import six import pytest -from flatten_dict import flatten, unflatten +from flatten_dict import flatten, unflatten, TReducerCallable +from flatten_dict.flatten_dict import TKeyIn from flatten_dict.reducers import ( tuple_reducer, path_reducer, @@ -21,9 +41,11 @@ make_splitter, ) +TNormalDict = Dict[str, Union[str, Dict[str, Union[str, Dict[str, str]]]]] + @pytest.fixture -def normal_dict(): +def normal_dict() -> TNormalDict: return { "a": "0", "b": { @@ -40,8 +62,11 @@ def normal_dict(): } +TFlatTupleDict = Dict[Tuple[str, ...], str] + + @pytest.fixture -def flat_tuple_dict(): +def flat_tuple_dict() -> TFlatTupleDict: return { ("a",): "0", ("b", "a"): "1.0", @@ -52,8 +77,11 @@ def flat_tuple_dict(): } +TFlatTupleDictDepth2 = Dict[Tuple[str, ...], Union[str, Dict[str, str]]] + + @pytest.fixture -def flat_tuple_dict_depth2(): +def flat_tuple_dict_depth2() -> TFlatTupleDictDepth2: return { ("a",): "0", ("b", "a"): "1.0", @@ -63,8 +91,17 @@ def flat_tuple_dict_depth2(): } +TNormalDictWithNestedLists = Dict[ + str, + Union[ + str, + List[Union[str, Dict[str, str], List[str], Dict[str, List[str]]]], + ], +] + + @pytest.fixture -def normal_dict_with_nested_lists(): +def normal_dict_with_nested_lists() -> TNormalDictWithNestedLists: return { "aaa": "0", "bbb": ["1.1", "1.2", "1.3"], @@ -78,7 +115,7 @@ def normal_dict_with_nested_lists(): @pytest.fixture -def flat_dict_with_nested_lists_with_list_syntax(): +def flat_dict_with_nested_lists_with_list_syntax() -> Dict[str, str]: return { "aaa": "0", "bbb[0]": "1.1", @@ -101,33 +138,41 @@ def flat_dict_with_nested_lists_with_list_syntax(): } -def get_flat_tuple_dict(flat_tuple_dict): +T = TypeVar("T") + + +def get_flat_tuple_dict(flat_tuple_dict: T) -> T: return flat_tuple_dict -def get_flat_path_dict(flat_tuple_dict): - return {os.path.join(*k): v for k, v in six.viewitems(flat_tuple_dict)} +def get_flat_path_dict(flat_tuple_dict: TFlatTupleDict) -> Dict[str, str]: + return {os.path.join(*k): v for k, v in flat_tuple_dict.items()} -def get_flat_underscore_dict(flat_tuple_dict): - return {"_".join(k): v for k, v in six.viewitems(flat_tuple_dict)} +def get_flat_underscore_dict(flat_tuple_dict: TFlatTupleDict) -> Dict[str, str]: + return {"_".join(k): v for k, v in flat_tuple_dict.items()} + + +TInvFlatTupleDict = Dict[str, Tuple[str, ...]] @pytest.fixture -def inv_flat_tuple_dict(flat_tuple_dict): - return {v: k for k, v in six.viewitems(flat_tuple_dict)} +def inv_flat_tuple_dict(flat_tuple_dict: TFlatTupleDict) -> TInvFlatTupleDict: + return {v: k for k, v in flat_tuple_dict.items()} -def test_flatten_dict(normal_dict, flat_tuple_dict): +def test_flatten_dict( + normal_dict: TNormalDict, flat_tuple_dict: TFlatTupleDict +) -> None: assert flatten(normal_dict) == flat_tuple_dict -def test_flatten_dict_invalid_depth_limit(normal_dict): +def test_flatten_dict_invalid_depth_limit(normal_dict: TNormalDict) -> None: with pytest.raises(ValueError): flatten(normal_dict, max_flatten_depth=0) -def test_flatten_dict_depth_limit_1(normal_dict): +def test_flatten_dict_depth_limit_1(normal_dict: TNormalDict) -> None: flattened = flatten(normal_dict, max_flatten_depth=1) values_before = sorted( flattened.values(), key=lambda x: json.dumps(x, sort_keys=True) @@ -138,15 +183,19 @@ def test_flatten_dict_depth_limit_1(normal_dict): assert values_before == values_after -def test_flatten_dict_depth_limit_2(normal_dict, flat_tuple_dict_depth2): +def test_flatten_dict_depth_limit_2( + normal_dict: TNormalDict, flat_tuple_dict_depth2: TFlatTupleDictDepth2 +) -> None: assert flatten(normal_dict, max_flatten_depth=2) == flat_tuple_dict_depth2 -def test_flatten_dict_irrelevant_depth_limit(normal_dict, flat_tuple_dict): +def test_flatten_dict_irrelevant_depth_limit( + normal_dict: TNormalDict, flat_tuple_dict: TFlatTupleDict +) -> None: assert flatten(normal_dict, max_flatten_depth=3) == flat_tuple_dict -def test_flatten_nonflattenable_type(): +def test_flatten_nonflattenable_type() -> None: with pytest.raises(ValueError): flatten([]) @@ -163,17 +212,24 @@ def test_flatten_nonflattenable_type(): ], ) def test_flatten_dict_with_reducer( - normal_dict, flat_tuple_dict, reducer, expected_flat_dict_func -): + normal_dict: TNormalDict, + flat_tuple_dict: TFlatTupleDict, + reducer: TReducerCallable, + expected_flat_dict_func: Callable[ + [TFlatTupleDict], Union[TFlatTupleDict, Dict[str, str]] + ], +) -> None: expected_flat_dict = expected_flat_dict_func(flat_tuple_dict) assert flatten(normal_dict, reducer=reducer) == expected_flat_dict -def test_flatten_dict_inverse(normal_dict, inv_flat_tuple_dict): +def test_flatten_dict_inverse( + normal_dict: TNormalDict, inv_flat_tuple_dict: TInvFlatTupleDict +) -> None: assert flatten(normal_dict, inverse=True) == inv_flat_tuple_dict -def test_flatten_dict_inverse_with_duplicated_value(normal_dict): +def test_flatten_dict_inverse_with_duplicated_value(normal_dict: TNormalDict) -> None: dup_val_dict = normal_dict.copy() dup_val_dict["a"] = "2.1.1" with pytest.raises(ValueError): @@ -181,9 +237,14 @@ def test_flatten_dict_inverse_with_duplicated_value(normal_dict): def test_flatten_dict_with_list_syntax( - normal_dict_with_nested_lists, flat_dict_with_nested_lists_with_list_syntax -): - def _reducer(parent_path, key, parent_obj): + normal_dict_with_nested_lists: TNormalDictWithNestedLists, + flat_dict_with_nested_lists_with_list_syntax: Dict[str, str], +) -> None: + def _reducer( + parent_path: Optional[Union[str, int]], + key: Union[str, int], + parent_obj: Union[Iterable[Any], Mapping[str, Any]], + ) -> Union[str, int]: if parent_path is None: return key elif isinstance(parent_obj, list): @@ -199,11 +260,15 @@ def _reducer(parent_path, key, parent_obj): ) -def test_unflatten_dict(normal_dict, flat_tuple_dict): +def test_unflatten_dict( + normal_dict: TNormalDict, flat_tuple_dict: TFlatTupleDict +) -> None: assert unflatten(flat_tuple_dict) == normal_dict -def test_unflatten_dict_inverse(normal_dict, inv_flat_tuple_dict): +def test_unflatten_dict_inverse( + normal_dict: TNormalDict, inv_flat_tuple_dict: TInvFlatTupleDict +) -> None: assert unflatten(inv_flat_tuple_dict, inverse=True) == normal_dict @@ -219,22 +284,30 @@ def test_unflatten_dict_inverse(normal_dict, inv_flat_tuple_dict): ], ) def test_unflatten_dict_with_splitter( - normal_dict, flat_tuple_dict, splitter, flat_dict_func -): + normal_dict: TNormalDict, + flat_tuple_dict: TFlatTupleDict, + splitter: Callable[[str], Tuple[Any, ...]], + flat_dict_func: Callable[[TFlatTupleDict], Dict[str, str]], +) -> None: flat_dict = flat_dict_func(flat_tuple_dict) assert unflatten(flat_dict, splitter=splitter) == normal_dict def test_unflatten_dict_inverse_with_duplicated_value( - flat_tuple_dict, inv_flat_tuple_dict -): + inv_flat_tuple_dict: TInvFlatTupleDict, +) -> None: inv_flat_tuple_dict["2.1.1"] = ("c", "b", "a") with pytest.raises(ValueError): unflatten(inv_flat_tuple_dict, inverse=True) +TDictWithLists = Dict[ + str, Union[str, Dict[str, Union[str, Dict[str, Union[str, Sequence[str]]]]]] +] + + @pytest.fixture -def dict_with_list(): +def dict_with_list() -> TDictWithLists: return { "a": "0", "b": { @@ -252,8 +325,11 @@ def dict_with_list(): } +TFlatTupleDictWithList = Dict[Tuple[str, ...], Union[str, Sequence[str]]] + + @pytest.fixture -def flat_tuple_dict_with_list(): +def flat_tuple_dict_with_list() -> TFlatTupleDictWithList: return { ("a",): "0", ("b", "a"): "1.0", @@ -265,8 +341,13 @@ def flat_tuple_dict_with_list(): } +TFlatTupleDictWithListDepth2 = Dict[ + Tuple[str, ...], Union[str, Dict[str, Union[str, Sequence[str]]]] +] + + @pytest.fixture -def flat_tuple_dict_with_list_depth2(): +def flat_tuple_dict_with_list_depth2() -> TFlatTupleDictWithListDepth2: return { ("a",): "0", ("b", "a"): "1.0", @@ -280,33 +361,42 @@ def flat_tuple_dict_with_list_depth2(): } -def test_flatten_dict_with_list(dict_with_list, flat_tuple_dict_with_list): +def test_flatten_dict_with_list( + dict_with_list: TDictWithLists, flat_tuple_dict_with_list: TFlatTupleDictWithList +) -> None: assert flatten(dict_with_list) == flat_tuple_dict_with_list -def test_flatten_dict_with_list_depth_limit_1(dict_with_list): - flattened = flatten(dict_with_list, max_flatten_depth=1) +def test_flatten_dict_with_list_depth_limit_1(dict_with_list: TDictWithLists) -> None: + # TODO: type of key should be possible to infer + flattened: Dict[Tuple[str, ...], str] = flatten(dict_with_list, max_flatten_depth=1) before = sorted(dict_with_list.items(), key=lambda x: x[0]) - after = sorted(flattened.items(), key=lambda x: x[0]) + _after = sorted(flattened.items(), key=lambda x: x[0]) # flatten with the default reducer transforms keys to tuples - after = [(x[0][0], x[1]) for x in after] + after = [(key, val) for (key,), val in _after] assert before == after def test_flatten_dict_with_list_depth_limit_2( - dict_with_list, flat_tuple_dict_with_list_depth2 -): + dict_with_list: TDictWithLists, + flat_tuple_dict_with_list_depth2: TFlatTupleDictWithListDepth2, +) -> None: assert ( flatten(dict_with_list, max_flatten_depth=2) == flat_tuple_dict_with_list_depth2 ) def test_flatten_dict_with_list_irrelevant_depth_limit( - dict_with_list, flat_tuple_dict_with_list -): + dict_with_list: TDictWithLists, flat_tuple_dict_with_list: TFlatTupleDictWithList +) -> None: assert flatten(dict_with_list, max_flatten_depth=3) == flat_tuple_dict_with_list +TFlatDictCallable = Callable[ + [TFlatTupleDictWithList], Union[TDictWithLists, TFlatTupleDictWithList] +] + + @pytest.mark.parametrize( "reducer, expected_flat_dict_func", [ @@ -319,13 +409,18 @@ def test_flatten_dict_with_list_irrelevant_depth_limit( ], ) def test_flatten_dict_with_list_with_reducer( - dict_with_list, flat_tuple_dict_with_list, reducer, expected_flat_dict_func -): + dict_with_list: TDictWithLists, + flat_tuple_dict_with_list: TFlatTupleDictWithList, + reducer: TReducerCallable, + expected_flat_dict_func: TFlatDictCallable, +) -> None: expected_flat_dict = expected_flat_dict_func(flat_tuple_dict_with_list) assert flatten(dict_with_list, reducer=reducer) == expected_flat_dict -def test_unflatten_dict_with_list(dict_with_list, flat_tuple_dict_with_list): +def test_unflatten_dict_with_list( + dict_with_list: TDictWithLists, flat_tuple_dict_with_list: TFlatTupleDictWithList +) -> None: assert unflatten(flat_tuple_dict_with_list) == dict_with_list @@ -341,14 +436,23 @@ def test_unflatten_dict_with_list(dict_with_list, flat_tuple_dict_with_list): ], ) def test_unflatten_dict_with_list_with_splitter( - dict_with_list, flat_tuple_dict_with_list, splitter, flat_dict_func -): + dict_with_list: TDictWithLists, + flat_tuple_dict_with_list: TFlatTupleDictWithList, + splitter: Callable[[TKeyIn], Tuple[str, ...]], + flat_dict_func: Callable[ + [TFlatTupleDictWithList], + Dict[TKeyIn, Union[str, List[str]]], + ], +) -> None: flat_dict = flat_dict_func(flat_tuple_dict_with_list) assert unflatten(flat_dict, splitter=splitter) == dict_with_list +TFlatTupleDictWithEnumeratedList = Dict[Tuple[Union[str, int], ...], str] + + @pytest.fixture -def flat_tuple_dict_with_enumerated_list(): +def flat_tuple_dict_with_enumerated_list() -> TFlatTupleDictWithEnumeratedList: return { ("a",): "0", ("b", "a"): "1.0", @@ -361,20 +465,26 @@ def flat_tuple_dict_with_enumerated_list(): def test_flatten_dict_with_list_with_enumerate_types( - dict_with_list, flat_tuple_dict_with_enumerated_list -): + dict_with_list: TDictWithLists, + flat_tuple_dict_with_enumerated_list: TFlatTupleDictWithEnumeratedList, +) -> None: assert ( flatten(dict_with_list, enumerate_types=(list,)) == flat_tuple_dict_with_enumerated_list ) -def test_flatten_list(): +def test_flatten_list() -> None: assert flatten([1, 2], enumerate_types=(list,)) == {(0,): 1, (1,): 2} +TDictWithGenerator = Dict[ + str, Union[str, Dict[str, Union[str, Dict[str, Union[str, Iterator[str]]]]]] +] + + @pytest.fixture -def dict_with_generator(): +def dict_with_generator() -> TDictWithGenerator: return { "a": "0", "b": { @@ -386,23 +496,29 @@ def dict_with_generator(): "b": { "a": "2.1.0", "b": ("2.1.1.%d" % i for i in range(2)), - "c": (i for i in ()), # empty generator + "c": (i for i in ""), # empty generator }, }, } def test_flatten_dict_with_generator_with_enumerate_types( - dict_with_generator, flat_tuple_dict_with_enumerated_list -): + dict_with_generator: TDictWithGenerator, + flat_tuple_dict_with_enumerated_list: TFlatTupleDictWithEnumeratedList, +) -> None: assert ( flatten(dict_with_generator, enumerate_types=(GeneratorType,)) == flat_tuple_dict_with_enumerated_list ) +TDictWithEmptyDict = Dict[ + str, Union[str, Dict[str, Union[str, Dict[str, Union[str, Dict]]]]] +] + + @pytest.fixture -def dict_with_empty_dict(): +def dict_with_empty_dict() -> TDictWithEmptyDict: return { "a": "0", "b": { @@ -420,8 +536,11 @@ def dict_with_empty_dict(): } +TFlatTupleDictWithEmptyDict = Dict[Tuple[str, ...], Union[str, Dict]] + + @pytest.fixture -def flat_tuple_dict_with_empty_dict(): +def flat_tuple_dict_with_empty_dict() -> TFlatTupleDictWithEmptyDict: return { ("a",): "0", ("b", "a"): "1.0", @@ -433,28 +552,41 @@ def flat_tuple_dict_with_empty_dict(): } -def test_flatten_dict_with_empty_dict(dict_with_empty_dict, flat_tuple_dict): +def test_flatten_dict_with_empty_dict( + dict_with_empty_dict: TDictWithEmptyDict, + flat_tuple_dict: TFlatTupleDictWithEmptyDict, +) -> None: assert flatten(dict_with_empty_dict) == flat_tuple_dict def test_flatten_dict_with_empty_dict_kept( - dict_with_empty_dict, flat_tuple_dict_with_empty_dict -): + dict_with_empty_dict: TDictWithEmptyDict, + flat_tuple_dict_with_empty_dict: TFlatTupleDictWithEmptyDict, +) -> None: assert ( flatten(dict_with_empty_dict, keep_empty_types=(dict,)) == flat_tuple_dict_with_empty_dict ) -def test_flatten_dict_with_keep_empty_types(normal_dict, flat_tuple_dict): +def test_flatten_dict_with_keep_empty_types( + normal_dict: TNormalDict, flat_tuple_dict: TFlatTupleDict +) -> None: assert flatten(normal_dict, keep_empty_types=(dict, str)) == flat_tuple_dict @pytest.mark.parametrize( "delimiter, delimiter_equivalent", [(".", "dot"), ("_", "underscore")] ) -def test_make_reducer(normal_dict, delimiter, delimiter_equivalent): - reducer = make_reducer(delimiter) +def test_make_reducer( + normal_dict: TNormalDict, + delimiter: str, + delimiter_equivalent: Literal["dot", "underscore"], +) -> None: + # use explicit type to narrow default reducer + reducer: Callable[ + [Union[str, int, None], Union[str, int]], Union[str, int] + ] = make_reducer(delimiter) flattened_dict_using_make_reducer = flatten(normal_dict, reducer=reducer) flattened_dict_using_equivalent_reducer = flatten( normal_dict, reducer=delimiter_equivalent @@ -465,7 +597,11 @@ def test_make_reducer(normal_dict, delimiter, delimiter_equivalent): @pytest.mark.parametrize( "delimiter, delimiter_equivalent", [(".", "dot"), ("_", "underscore")] ) -def test_make_splitter(normal_dict, delimiter, delimiter_equivalent): +def test_make_splitter( + normal_dict: TNormalDict, + delimiter: str, + delimiter_equivalent: Literal["dot", "underscore"], +) -> None: splitter = make_splitter(delimiter) flat_dict = flatten(normal_dict, delimiter_equivalent) unflattened_dict_using_make_splitter = unflatten(flat_dict, splitter=splitter) diff --git a/tox.ini b/tox.ini index fa2476b..bd7eb79 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] isolated_build = true -envlist = py{27, 36, 37, 38, 39, 310}, flake8 +envlist = py{36, 37, 38, 39, 310}, py{,36, 37, 38, 39, 310}-type, flake8 [testenv] deps = @@ -20,3 +20,9 @@ commands = # use poetry to install all dev dependencies poetry install poetry run flake8 + +[testenv:py{, 36, 37, 38, 39, 310}-type] +deps = + mypy +commands = + mypy src