diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index c778bf1dd..8369cec24 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -1,4 +1,5 @@ name: Run CD +permissions: read-all on: workflow_dispatch: @@ -134,11 +135,12 @@ jobs: name: Upload release artifact runs-on: ubuntu-latest if: github.triggering_actor == 'mgkwill' || github.triggering_actor == 'PhilippPlank' || github.triggering_actor == 'tim-shea' - outputs: - api-token: ${{ steps.mint-token.outputs.api-token}} + environment: + name: pypi + url: https://pypi.org/p/lava-nc/ permissions: - contents: write id-token: write + contents: write needs: [build-artifacts, test-artifact-install, test-artifact-use] steps: @@ -184,27 +186,12 @@ jobs: generateReleaseNotes: true makeLatest: true - - name: Mint Github API token - id: mint-token - run: | - # retrieve OIDC token - resp=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ - "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=pypi") - oidc_token=$(jq '.value' <<< "${resp}") - - # exchange OIDC token for API token - resp=$(curl -X POST https://pypi.org/_/oidc/github/mint-token -d "{\"token\": \"${oidc_token}\"}") - api_token=$(jq '.token' <<< "${resp}") - - # mask the API token, to prevent leaking it - echo "::add-mask::${api_token}" - - echo "api-token=${api_token}" >> "${GITHUB_OUTPUT}" - - name: Publish to PyPI if: steps.check-version.outputs.prerelease != 'true' run: | - poetry config pypi-token.pypi ${{ steps.mint-token.outputs.api-token }} mkdir dist cp lava* dist/. - poetry publish + + - name: Publish package distributions to PyPI + if: steps.check-version.outputs.prerelease != 'true' + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0374b531..200c8dd8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,5 @@ name: Run CI +permissions: read-all on: push: branches: @@ -20,7 +21,7 @@ jobs: lfs: true - name: setup CI - uses: lava-nc/ci-setup-composite-action@v1.2 + uses: lava-nc/ci-setup-composite-action@v1.5.10_py3.10 with: repository: 'Lava' @@ -38,7 +39,7 @@ jobs: lfs: true - name: setup CI - uses: lava-nc/ci-setup-composite-action@v1.2 + uses: lava-nc/ci-setup-composite-action@v1.5.10_py3.10 with: repository: 'Lava' @@ -54,14 +55,14 @@ jobs: runs-on: ${{ matrix.operating-system }} strategy: matrix: - operating-system: [ubuntu-latest, windows-latest, macos-latest] + operating-system: [ubuntu-latest, windows-latest, macos-13] steps: - uses: actions/checkout@v3 with: lfs: true - name: setup CI - uses: lava-nc/ci-setup-composite-action@v1.2 + uses: lava-nc/ci-setup-composite-action@v1.5.10_py3.10 with: repository: 'Lava' diff --git a/.github/workflows/codacy_coverage_reporter.yml b/.github/workflows/codacy_coverage_reporter.yml index a6826c9c5..f5c426c05 100644 --- a/.github/workflows/codacy_coverage_reporter.yml +++ b/.github/workflows/codacy_coverage_reporter.yml @@ -1,5 +1,5 @@ name: Codacy Coverage Reporter - +permissions: read-all on: workflow_run: workflows: ["Run CI"] diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml index 72c8c20c0..896bf413f 100644 --- a/.github/workflows/issues.yml +++ b/.github/workflows/issues.yml @@ -1,5 +1,5 @@ name: Add new issues to the NCL planning project and label them - +permissions: {} on: issues: types: @@ -10,6 +10,7 @@ on: jobs: add-to-project: name: Add issue to project + permissions: {} runs-on: ubuntu-latest steps: - uses: actions/add-to-project@v0.4.0 diff --git a/.gitignore b/.gitignore index cd5d1d84b..7d71837a3 100644 --- a/.gitignore +++ b/.gitignore @@ -145,3 +145,5 @@ dmypy.json .idea/ .vscode/ .history/ +.flakeheaven_cache/ +tutorials/in_depth/results/ diff --git a/.gitmodules b/.gitmodules index e11057ce3..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "docs"] - path = docs - url = https://github.com/lava-nc/lava-docs.git diff --git a/README.md b/README.md index 9c4003a75..a6fd40b32 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ cd $HOME curl -sSL https://install.python-poetry.org | python3 - git clone git@github.com:lava-nc/lava.git cd lava -git checkout v0.8.0 +git checkout v0.9.0 ./utils/githook/install-hook.sh poetry config virtualenvs.in-project true poetry install @@ -90,7 +90,7 @@ pytest cd $HOME git clone git@github.com:lava-nc/lava.git cd lava -git checkout v0.8.0 +git checkout v0.9.0 python3 -m venv .venv .venv\Scripts\activate pip install -U pip @@ -186,7 +186,7 @@ python -m venv .venv source .venv/bin/activate ## Or Windows: .venv\Scripts\activate pip install -U pip # Substitute lava version needed for lava-nc-.tar.gz below -pip install lava-nc-0.8.0.tar.gz +pip install lava-nc-0.9.0.tar.gz ``` ## Linting, testing, documentation and packaging diff --git a/docs b/docs deleted file mode 160000 index 9492b5759..000000000 --- a/docs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9492b5759b081812e1d111e6f188d2ee2bba94d4 diff --git a/poetry.lock b/poetry.lock index 40a7041ff..9d12c8b21 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,25 +1,25 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.16" +description = "A light, configurable Sphinx theme" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] [[package]] name = "appnope" -version = "0.1.3" +version = "0.1.4" description = "Disable App Nap on macOS >= 10.9" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, ] [[package]] @@ -35,13 +35,13 @@ files = [ [[package]] name = "asteval" -version = "0.9.31" +version = "0.9.33" description = "Safe, minimalistic evaluator of python expression using ast module" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "asteval-0.9.31-py3-none-any.whl", hash = "sha256:2761750c184d97707c292b62df3b10e330a809a2201721acc435a2b89a114263"}, - {file = "asteval-0.9.31.tar.gz", hash = "sha256:a2da066b6696dba9835c5f7dec63e0ffb5bd2b4e3bb5f0b9a604aeafb17d833d"}, + {file = "asteval-0.9.33-py3-none-any.whl", hash = "sha256:aae3a0308575a545c8cecc43a6632219e6a90963a56380c74632cf54311e43bf"}, + {file = "asteval-0.9.33.tar.gz", hash = "sha256:94981701f4d252c88aa5e821121b1aabef73a003da138fc6405169c9e675d24d"}, ] [package.extras] @@ -52,38 +52,40 @@ test = ["coverage", "pytest", "pytest-cov"] [[package]] name = "asttokens" -version = "2.2.1" +version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.2.1-py2.py3-none-any.whl", hash = "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"}, - {file = "asttokens-2.2.1.tar.gz", hash = "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3"}, + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, ] [package.dependencies] -six = "*" +six = ">=1.12.0" [package.extras] -test = ["astroid", "pytest"] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "autopep8" @@ -102,28 +104,17 @@ toml = "*" [[package]] name = "babel" -version = "2.12.1" +version = "2.15.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, - {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] -[package.dependencies] -pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} - -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -optional = false -python-versions = "*" -files = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "bandit" @@ -149,31 +140,34 @@ yaml = ["PyYAML"] [[package]] name = "beautifulsoup4" -version = "4.12.2" +version = "4.12.3" description = "Screen-scraping library" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, - {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] [package.dependencies] soupsieve = ">1.2" [package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] [[package]] name = "bleach" -version = "6.0.0" +version = "6.1.0" description = "An easy safelist-based HTML-sanitizing tool." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "bleach-6.0.0-py3-none-any.whl", hash = "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"}, - {file = "bleach-6.0.0.tar.gz", hash = "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414"}, + {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, + {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, ] [package.dependencies] @@ -181,133 +175,124 @@ six = ">=1.9.0" webencodings = "*" [package.extras] -css = ["tinycss2 (>=1.1.0,<1.2)"] +css = ["tinycss2 (>=1.1.0,<1.3)"] [[package]] name = "build" -version = "0.10.0" +version = "1.2.1" description = "A simple, correct Python build frontend" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.8" files = [ - {file = "build-0.10.0-py3-none-any.whl", hash = "sha256:af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171"}, - {file = "build-0.10.0.tar.gz", hash = "sha256:d5b71264afdb5951d6704482aac78de887c80691c52b88a9ad195983ca2c9269"}, + {file = "build-1.2.1-py3-none-any.whl", hash = "sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4"}, + {file = "build-1.2.1.tar.gz", hash = "sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d"}, ] [package.dependencies] colorama = {version = "*", markers = "os_name == \"nt\""} -packaging = ">=19.0" +importlib-metadata = {version = ">=4.6", markers = "python_full_version < \"3.10.2\""} +packaging = ">=19.1" pyproject_hooks = "*" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [package.extras] -docs = ["furo (>=2021.08.31)", "sphinx (>=4.0,<5.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)"] -test = ["filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "toml (>=0.10.0)", "wheel (>=0.36.0)"] -typing = ["importlib-metadata (>=5.1)", "mypy (==0.991)", "tomli", "typing-extensions (>=3.7.4.3)"] +docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"] +test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"] +typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"] +uv = ["uv (>=0.1.18)"] virtualenv = ["virtualenv (>=20.0.35)"] [[package]] name = "cachecontrol" -version = "0.12.14" +version = "0.14.0" description = "httplib2 caching for requests" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "CacheControl-0.12.14-py2.py3-none-any.whl", hash = "sha256:1c2939be362a70c4e5f02c6249462b3b7a24441e4f1ced5e9ef028172edf356a"}, - {file = "CacheControl-0.12.14.tar.gz", hash = "sha256:d1087f45781c0e00616479bfd282c78504371ca71da017b49df9f5365a95feba"}, + {file = "cachecontrol-0.14.0-py3-none-any.whl", hash = "sha256:f5bf3f0620c38db2e5122c0726bdebb0d16869de966ea6a2befe92470b740ea0"}, + {file = "cachecontrol-0.14.0.tar.gz", hash = "sha256:7db1195b41c81f8274a7bbd97c956f44e8348265a1bc7641c37dfebc39f0c938"}, ] [package.dependencies] -lockfile = {version = ">=0.9", optional = true, markers = "extra == \"filecache\""} -msgpack = ">=0.5.2" -requests = "*" +filelock = {version = ">=3.8.0", optional = true, markers = "extra == \"filecache\""} +msgpack = ">=0.5.2,<2.0.0" +requests = ">=2.16.0" [package.extras] -filecache = ["lockfile (>=0.9)"] +dev = ["CacheControl[filecache,redis]", "black", "build", "cherrypy", "furo", "mypy", "pytest", "pytest-cov", "sphinx", "sphinx-copybutton", "tox", "types-redis", "types-requests"] +filecache = ["filelock (>=3.8.0)"] redis = ["redis (>=2.10.5)"] [[package]] name = "certifi" -version = "2023.7.22" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] name = "cffi" -version = "1.15.1" +version = "1.16.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] [package.dependencies] @@ -315,102 +300,117 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, - {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] name = "cleo" -version = "2.0.1" +version = "2.1.0" description = "Cleo allows you to create beautiful and testable command-line interfaces." optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "cleo-2.0.1-py3-none-any.whl", hash = "sha256:6eb133670a3ed1f3b052d53789017b6e50fca66d1287e6e6696285f4cb8ea448"}, - {file = "cleo-2.0.1.tar.gz", hash = "sha256:eb4b2e1f3063c11085cebe489a6e9124163c226575a3c3be69b2e51af4a15ec5"}, + {file = "cleo-2.1.0-py3-none-any.whl", hash = "sha256:4a31bd4dd45695a64ee3c4758f583f134267c2bc518d8ae9a29cf237d009b07e"}, + {file = "cleo-2.1.0.tar.gz", hash = "sha256:0b2c880b5d13660a7ea651001fb4acb527696c01f15c9ee650f377aa543fd523"}, ] [package.dependencies] crashtest = ">=0.4.1,<0.5.0" -rapidfuzz = ">=2.2.0,<3.0.0" +rapidfuzz = ">=3.0.0,<4.0.0" [[package]] name = "colorama" @@ -425,84 +425,83 @@ files = [ [[package]] name = "comm" -version = "0.1.3" +version = "0.2.2" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "comm-0.1.3-py3-none-any.whl", hash = "sha256:16613c6211e20223f215fc6d3b266a247b6e2641bf4e0a3ad34cb1aff2aa3f37"}, - {file = "comm-0.1.3.tar.gz", hash = "sha256:a61efa9daffcfbe66fd643ba966f846a624e4e6d6767eda9cf6e993aadaab93e"}, + {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, + {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, ] [package.dependencies] -traitlets = ">=5.3" +traitlets = ">=4" [package.extras] -lint = ["black (>=22.6.0)", "mdformat (>0.7)", "mdformat-gfm (>=0.3.5)", "ruff (>=0.0.156)"] test = ["pytest"] -typing = ["mypy (>=0.990)"] [[package]] name = "contourpy" -version = "1.1.0" +version = "1.2.1" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false -python-versions = ">=3.8" -files = [ - {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, - {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, - {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, - {file = "contourpy-1.1.0-cp310-cp310-win32.whl", hash = "sha256:9b2dd2ca3ac561aceef4c7c13ba654aaa404cf885b187427760d7f7d4c57cff8"}, - {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, - {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, - {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, - {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, - {file = "contourpy-1.1.0-cp311-cp311-win32.whl", hash = "sha256:edb989d31065b1acef3828a3688f88b2abb799a7db891c9e282df5ec7e46221b"}, - {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, - {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, - {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, - {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, - {file = "contourpy-1.1.0-cp38-cp38-win32.whl", hash = "sha256:108dfb5b3e731046a96c60bdc46a1a0ebee0760418951abecbe0fc07b5b93b27"}, - {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, - {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, - {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, - {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, - {file = "contourpy-1.1.0-cp39-cp39-win32.whl", hash = "sha256:71551f9520f008b2950bef5f16b0e3587506ef4f23c734b71ffb7b89f8721999"}, - {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, - {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, -] - -[package.dependencies] -numpy = ">=1.16" +python-versions = ">=3.9" +files = [ + {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"}, + {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"}, + {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"}, + {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"}, + {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"}, + {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"}, + {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"}, + {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"}, + {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"}, + {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"}, + {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"}, +] + +[package.dependencies] +numpy = ">=1.20" [package.extras] bokeh = ["bokeh", "selenium"] -docs = ["furo", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" @@ -582,60 +581,68 @@ files = [ [[package]] name = "cryptography" -version = "41.0.4" +version = "43.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839"}, - {file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13"}, - {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143"}, - {file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397"}, - {file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860"}, - {file = "cryptography-41.0.4-cp37-abi3-win32.whl", hash = "sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd"}, - {file = "cryptography-41.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829"}, - {file = "cryptography-41.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9"}, - {file = "cryptography-41.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6"}, - {file = "cryptography-41.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311"}, - {file = "cryptography-41.0.4.tar.gz", hash = "sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a"}, -] - -[package.dependencies] -cffi = ">=1.12" + {file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"}, + {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"}, + {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"}, + {file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"}, + {file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"}, + {file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"}, + {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"}, + {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"}, + {file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"}, + {file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1"}, + {file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] nox = ["nox"] -pep8test = ["black", "check-sdist", "mypy", "ruff"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.0)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] name = "cycler" -version = "0.11.0" +version = "0.12.1" description = "Composable style cycles" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, ] +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + [[package]] name = "darglint" version = "1.8.1" @@ -649,29 +656,33 @@ files = [ [[package]] name = "debugpy" -version = "1.6.7" +version = "1.8.2" description = "An implementation of the Debug Adapter Protocol for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "debugpy-1.6.7-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b3e7ac809b991006ad7f857f016fa92014445085711ef111fdc3f74f66144096"}, - {file = "debugpy-1.6.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3876611d114a18aafef6383695dfc3f1217c98a9168c1aaf1a02b01ec7d8d1e"}, - {file = "debugpy-1.6.7-cp310-cp310-win32.whl", hash = "sha256:33edb4afa85c098c24cc361d72ba7c21bb92f501104514d4ffec1fb36e09c01a"}, - {file = "debugpy-1.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:ed6d5413474e209ba50b1a75b2d9eecf64d41e6e4501977991cdc755dc83ab0f"}, - {file = "debugpy-1.6.7-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:38ed626353e7c63f4b11efad659be04c23de2b0d15efff77b60e4740ea685d07"}, - {file = "debugpy-1.6.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279d64c408c60431c8ee832dfd9ace7c396984fd7341fa3116aee414e7dcd88d"}, - {file = "debugpy-1.6.7-cp37-cp37m-win32.whl", hash = "sha256:dbe04e7568aa69361a5b4c47b4493d5680bfa3a911d1e105fbea1b1f23f3eb45"}, - {file = "debugpy-1.6.7-cp37-cp37m-win_amd64.whl", hash = "sha256:f90a2d4ad9a035cee7331c06a4cf2245e38bd7c89554fe3b616d90ab8aab89cc"}, - {file = "debugpy-1.6.7-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:5224eabbbeddcf1943d4e2821876f3e5d7d383f27390b82da5d9558fd4eb30a9"}, - {file = "debugpy-1.6.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bae1123dff5bfe548ba1683eb972329ba6d646c3a80e6b4c06cd1b1dd0205e9b"}, - {file = "debugpy-1.6.7-cp38-cp38-win32.whl", hash = "sha256:9cd10cf338e0907fdcf9eac9087faa30f150ef5445af5a545d307055141dd7a4"}, - {file = "debugpy-1.6.7-cp38-cp38-win_amd64.whl", hash = "sha256:aaf6da50377ff4056c8ed470da24632b42e4087bc826845daad7af211e00faad"}, - {file = "debugpy-1.6.7-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:0679b7e1e3523bd7d7869447ec67b59728675aadfc038550a63a362b63029d2c"}, - {file = "debugpy-1.6.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de86029696e1b3b4d0d49076b9eba606c226e33ae312a57a46dca14ff370894d"}, - {file = "debugpy-1.6.7-cp39-cp39-win32.whl", hash = "sha256:d71b31117779d9a90b745720c0eab54ae1da76d5b38c8026c654f4a066b0130a"}, - {file = "debugpy-1.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:c0ff93ae90a03b06d85b2c529eca51ab15457868a377c4cc40a23ab0e4e552a3"}, - {file = "debugpy-1.6.7-py2.py3-none-any.whl", hash = "sha256:53f7a456bc50706a0eaabecf2d3ce44c4d5010e46dfc65b6b81a518b42866267"}, - {file = "debugpy-1.6.7.zip", hash = "sha256:c4c2f0810fa25323abfdfa36cbbbb24e5c3b1a42cb762782de64439c575d67f2"}, + {file = "debugpy-1.8.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7ee2e1afbf44b138c005e4380097d92532e1001580853a7cb40ed84e0ef1c3d2"}, + {file = "debugpy-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f8c3f7c53130a070f0fc845a0f2cee8ed88d220d6b04595897b66605df1edd6"}, + {file = "debugpy-1.8.2-cp310-cp310-win32.whl", hash = "sha256:f179af1e1bd4c88b0b9f0fa153569b24f6b6f3de33f94703336363ae62f4bf47"}, + {file = "debugpy-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:0600faef1d0b8d0e85c816b8bb0cb90ed94fc611f308d5fde28cb8b3d2ff0fe3"}, + {file = "debugpy-1.8.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8a13417ccd5978a642e91fb79b871baded925d4fadd4dfafec1928196292aa0a"}, + {file = "debugpy-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acdf39855f65c48ac9667b2801234fc64d46778021efac2de7e50907ab90c634"}, + {file = "debugpy-1.8.2-cp311-cp311-win32.whl", hash = "sha256:2cbd4d9a2fc5e7f583ff9bf11f3b7d78dfda8401e8bb6856ad1ed190be4281ad"}, + {file = "debugpy-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:d3408fddd76414034c02880e891ea434e9a9cf3a69842098ef92f6e809d09afa"}, + {file = "debugpy-1.8.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:5d3ccd39e4021f2eb86b8d748a96c766058b39443c1f18b2dc52c10ac2757835"}, + {file = "debugpy-1.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62658aefe289598680193ff655ff3940e2a601765259b123dc7f89c0239b8cd3"}, + {file = "debugpy-1.8.2-cp312-cp312-win32.whl", hash = "sha256:bd11fe35d6fd3431f1546d94121322c0ac572e1bfb1f6be0e9b8655fb4ea941e"}, + {file = "debugpy-1.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:15bc2f4b0f5e99bf86c162c91a74c0631dbd9cef3c6a1d1329c946586255e859"}, + {file = "debugpy-1.8.2-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:5a019d4574afedc6ead1daa22736c530712465c0c4cd44f820d803d937531b2d"}, + {file = "debugpy-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40f062d6877d2e45b112c0bbade9a17aac507445fd638922b1a5434df34aed02"}, + {file = "debugpy-1.8.2-cp38-cp38-win32.whl", hash = "sha256:c78ba1680f1015c0ca7115671fe347b28b446081dada3fedf54138f44e4ba031"}, + {file = "debugpy-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cf327316ae0c0e7dd81eb92d24ba8b5e88bb4d1b585b5c0d32929274a66a5210"}, + {file = "debugpy-1.8.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1523bc551e28e15147815d1397afc150ac99dbd3a8e64641d53425dba57b0ff9"}, + {file = "debugpy-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e24ccb0cd6f8bfaec68d577cb49e9c680621c336f347479b3fce060ba7c09ec1"}, + {file = "debugpy-1.8.2-cp39-cp39-win32.whl", hash = "sha256:7f8d57a98c5a486c5c7824bc0b9f2f11189d08d73635c326abef268f83950326"}, + {file = "debugpy-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:16c8dcab02617b75697a0a925a62943e26a0330da076e2a10437edd9f0bf3755"}, + {file = "debugpy-1.8.2-py2.py3-none-any.whl", hash = "sha256:16e16df3a98a35c63c3ab1e4d19be4cbc7fdda92d9ddc059294f18910928e0ca"}, + {file = "debugpy-1.8.2.zip", hash = "sha256:95378ed08ed2089221896b9b3a8d021e642c24edc8fef20e5d4342ca8be65c00"}, ] [[package]] @@ -698,13 +709,13 @@ files = [ [[package]] name = "distlib" -version = "0.3.7" +version = "0.3.8" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, - {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] [[package]] @@ -720,67 +731,80 @@ files = [ [[package]] name = "dulwich" -version = "0.21.5" +version = "0.21.7" description = "Python Git Library" optional = false python-versions = ">=3.7" files = [ - {file = "dulwich-0.21.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8864719bc176cdd27847332a2059127e2f7bab7db2ff99a999873cb7fff54116"}, - {file = "dulwich-0.21.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3800cdc17d144c1f7e114972293bd6c46688f5bcc2c9228ed0537ded72394082"}, - {file = "dulwich-0.21.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2f676bfed8146966fe934ee734969d7d81548fbd250a8308582973670a9dab1"}, - {file = "dulwich-0.21.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db330fb59fe3b9d253bdf0e49a521739db83689520c4921ab1c5242aaf77b82"}, - {file = "dulwich-0.21.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e8f6d4f4f4d01dd1d3c968e486d4cd77f96f772da7265941bc506de0944ddb9"}, - {file = "dulwich-0.21.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1cc0c9ba19ac1b2372598802bc9201a9c45e5d6f1f7a80ec40deeb10acc4e9ae"}, - {file = "dulwich-0.21.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61e10242b5a7a82faa8996b2c76239cfb633620b02cdd2946e8af6e7eb31d651"}, - {file = "dulwich-0.21.5-cp310-cp310-win32.whl", hash = "sha256:7f357639b56146a396f48e5e0bc9bbaca3d6d51c8340bd825299272b588fff5f"}, - {file = "dulwich-0.21.5-cp310-cp310-win_amd64.whl", hash = "sha256:891d5c73e2b66d05dbb502e44f027dc0dbbd8f6198bc90dae348152e69d0befc"}, - {file = "dulwich-0.21.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45d6198e804b539708b73a003419e48fb42ff2c3c6dd93f63f3b134dff6dd259"}, - {file = "dulwich-0.21.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c2a565d4e704d7f784cdf9637097141f6d47129c8fffc2fac699d57cb075a169"}, - {file = "dulwich-0.21.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:823091d6b6a1ea07dc4839c9752198fb39193213d103ac189c7669736be2eaff"}, - {file = "dulwich-0.21.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2c9931b657f2206abec0964ec2355ee2c1e04d05f8864e823ffa23c548c4548"}, - {file = "dulwich-0.21.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dc358c2ee727322a09b7c6da43d47a1026049dbd3ad8d612eddca1f9074b298"}, - {file = "dulwich-0.21.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6155ab7388ee01c670f7c5d8003d4e133eebebc7085a856c007989f0ba921b36"}, - {file = "dulwich-0.21.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a605e10d72f90a39ea2e634fbfd80f866fc4df29a02ea6db52ae92e5fd4a2003"}, - {file = "dulwich-0.21.5-cp311-cp311-win32.whl", hash = "sha256:daa607370722c3dce99a0022397c141caefb5ed32032a4f72506f4817ea6405b"}, - {file = "dulwich-0.21.5-cp311-cp311-win_amd64.whl", hash = "sha256:5e56b2c1911c344527edb2bf1a4356e2fb7e086b1ba309666e1e5c2224cdca8a"}, - {file = "dulwich-0.21.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:85d3401d08b1ec78c7d58ae987c4bb7b768a438f3daa74aeb8372bebc7fb16fa"}, - {file = "dulwich-0.21.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90479608e49db93d8c9e4323bc0ec5496678b535446e29d8fd67dc5bbb5d51bf"}, - {file = "dulwich-0.21.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9a6bf99f57bcac4c77fc60a58f1b322c91cc4d8c65dc341f76bf402622f89cb"}, - {file = "dulwich-0.21.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3e68b162af2aae995355e7920f89d50d72b53d56021e5ac0a546d493b17cbf7e"}, - {file = "dulwich-0.21.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0ab86d6d42e385bf3438e70f3c9b16de68018bd88929379e3484c0ef7990bd3c"}, - {file = "dulwich-0.21.5-cp37-cp37m-win32.whl", hash = "sha256:f2eeca6d61366cf5ee8aef45bed4245a67d4c0f0d731dc2383eabb80fa695683"}, - {file = "dulwich-0.21.5-cp37-cp37m-win_amd64.whl", hash = "sha256:1b20a3656b48c941d49c536824e1e5278a695560e8de1a83b53a630143c4552e"}, - {file = "dulwich-0.21.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3932b5e17503b265a85f1eda77ede647681c3bab53bc9572955b6b282abd26ea"}, - {file = "dulwich-0.21.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6616132d219234580de88ceb85dd51480dc43b1bdc05887214b8dd9cfd4a9d40"}, - {file = "dulwich-0.21.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:eaf6c7fb6b13495c19c9aace88821c2ade3c8c55b4e216cd7cc55d3e3807d7fa"}, - {file = "dulwich-0.21.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be12a46f73023970125808a4a78f610c055373096c1ecea3280edee41613eba8"}, - {file = "dulwich-0.21.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baecef0d8b9199822c7912876a03a1af17833f6c0d461efb62decebd45897e49"}, - {file = "dulwich-0.21.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:82f632afb9c7c341a875d46aaa3e6c5e586c7a64ce36c9544fa400f7e4f29754"}, - {file = "dulwich-0.21.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82cdf482f8f51fcc965ffad66180b54a9abaea9b1e985a32e1acbfedf6e0e363"}, - {file = "dulwich-0.21.5-cp38-cp38-win32.whl", hash = "sha256:c8ded43dc0bd2e65420eb01e778034be5ca7f72e397a839167eda7dcb87c4248"}, - {file = "dulwich-0.21.5-cp38-cp38-win_amd64.whl", hash = "sha256:2aba0fdad2a19bd5bb3aad6882580cb33359c67b48412ccd4cfccd932012b35e"}, - {file = "dulwich-0.21.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fd4ad079758514375f11469e081723ba8831ce4eaa1a64b41f06a3a866d5ac34"}, - {file = "dulwich-0.21.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7fe62685bf356bfb4d0738f84a3fcf0d1fc9e11fee152e488a20b8c66a52429e"}, - {file = "dulwich-0.21.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aae448da7d80306dda4fc46292fed7efaa466294571ab3448be16714305076f1"}, - {file = "dulwich-0.21.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b24cb1fad0525dba4872e9381bc576ea2a6dcdf06b0ed98f8e953e3b1d719b89"}, - {file = "dulwich-0.21.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e39b7c2c9bda6acae83b25054650a8bb7e373e886e2334721d384e1479bf04b"}, - {file = "dulwich-0.21.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26456dba39d1209fca17187db06967130e27eeecad2b3c2bbbe63467b0bf09d6"}, - {file = "dulwich-0.21.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:281310644e02e3aa6d76bcaffe2063b9031213c4916b5f1a6e68c25bdecfaba4"}, - {file = "dulwich-0.21.5-cp39-cp39-win32.whl", hash = "sha256:4814ca3209dabe0fe7719e9545fbdad7f8bb250c5a225964fe2a31069940c4cf"}, - {file = "dulwich-0.21.5-cp39-cp39-win_amd64.whl", hash = "sha256:c922a4573267486be0ef85216f2da103fb38075b8465dc0e90457843884e4860"}, - {file = "dulwich-0.21.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e52b20c4368171b7d32bd3ab0f1d2402e76ad4f2ea915ff9aa73bc9fa2b54d6d"}, - {file = "dulwich-0.21.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeb736d777ee21f2117a90fc453ee181aa7eedb9e255b5ef07c51733f3fe5cb6"}, - {file = "dulwich-0.21.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e8a79c1ed7166f32ad21974fa98d11bf6fd74e94a47e754c777c320e01257c6"}, - {file = "dulwich-0.21.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b943517e30bd651fbc275a892bb96774f3893d95fe5a4dedd84496a98eaaa8ab"}, - {file = "dulwich-0.21.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:32493a456358a3a6c15bbda07106fc3d4cc50834ee18bc7717968d18be59b223"}, - {file = "dulwich-0.21.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0aa44b812d978fc22a04531f5090c3c369d5facd03fa6e0501d460a661800c7f"}, - {file = "dulwich-0.21.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f46bcb6777e5f9f4af24a2bd029e88b77316269d24ce66be590e546a0d8f7b7"}, - {file = "dulwich-0.21.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a917fd3b4493db3716da2260f16f6b18f68d46fbe491d851d154fc0c2d984ae4"}, - {file = "dulwich-0.21.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:684c52cff867d10c75a7238151ca307582b3d251bbcd6db9e9cffbc998ef804e"}, - {file = "dulwich-0.21.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9019189d7a8f7394df6a22cd5b484238c5776e42282ad5d6d6c626b4c5f43597"}, - {file = "dulwich-0.21.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:494024f74c2eef9988adb4352b3651ac1b6c0466176ec62b69d3d3672167ba68"}, - {file = "dulwich-0.21.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f9b6ac1b1c67fc6083c42b7b6cd3b211292c8a6517216c733caf23e8b103ab6d"}, - {file = "dulwich-0.21.5.tar.gz", hash = "sha256:70955e4e249ddda6e34a4636b90f74e931e558f993b17c52570fa6144b993103"}, + {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d4c0110798099bb7d36a110090f2688050703065448895c4f53ade808d889dd3"}, + {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2bc12697f0918bee324c18836053644035362bb3983dc1b210318f2fed1d7132"}, + {file = "dulwich-0.21.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:471305af74790827fcbafe330fc2e8bdcee4fb56ca1177c8c481b1c8f806c4a4"}, + {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54c9d0e845be26f65f954dff13a1cd3f2b9739820c19064257b8fd7435ab263"}, + {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12d61334a575474e707614f2e93d6ed4cdae9eb47214f9277076d9e5615171d3"}, + {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e274cebaf345f0b1e3b70197f2651de92b652386b68020cfd3bf61bc30f6eaaa"}, + {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:817822f970e196e757ae01281ecbf21369383285b9f4a83496312204cf889b8c"}, + {file = "dulwich-0.21.7-cp310-cp310-win32.whl", hash = "sha256:7836da3f4110ce684dcd53489015fb7fa94ed33c5276e3318b8b1cbcb5b71e08"}, + {file = "dulwich-0.21.7-cp310-cp310-win_amd64.whl", hash = "sha256:4a043b90958cec866b4edc6aef5fe3c2c96a664d0b357e1682a46f6c477273c4"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ce8db196e79c1f381469410d26fb1d8b89c6b87a4e7f00ff418c22a35121405c"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:62bfb26bdce869cd40be443dfd93143caea7089b165d2dcc33de40f6ac9d812a"}, + {file = "dulwich-0.21.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c01a735b9a171dcb634a97a3cec1b174cfbfa8e840156870384b633da0460f18"}, + {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa4d14767cf7a49c9231c2e52cb2a3e90d0c83f843eb6a2ca2b5d81d254cf6b9"}, + {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bca4b86e96d6ef18c5bc39828ea349efb5be2f9b1f6ac9863f90589bac1084d"}, + {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a7b5624b02ef808cdc62dabd47eb10cd4ac15e8ac6df9e2e88b6ac6b40133673"}, + {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c3a539b4696a42fbdb7412cb7b66a4d4d332761299d3613d90a642923c7560e1"}, + {file = "dulwich-0.21.7-cp311-cp311-win32.whl", hash = "sha256:675a612ce913081beb0f37b286891e795d905691dfccfb9bf73721dca6757cde"}, + {file = "dulwich-0.21.7-cp311-cp311-win_amd64.whl", hash = "sha256:460ba74bdb19f8d498786ae7776745875059b1178066208c0fd509792d7f7bfc"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4c51058ec4c0b45dc5189225b9e0c671b96ca9713c1daf71d622c13b0ab07681"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4bc4c5366eaf26dda3fdffe160a3b515666ed27c2419f1d483da285ac1411de0"}, + {file = "dulwich-0.21.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a0650ec77d89cb947e3e4bbd4841c96f74e52b4650830112c3057a8ca891dc2f"}, + {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f18f0a311fb7734b033a3101292b932158cade54b74d1c44db519e42825e5a2"}, + {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c589468e5c0cd84e97eb7ec209ab005a2cb69399e8c5861c3edfe38989ac3a8"}, + {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d62446797163317a397a10080c6397ffaaca51a7804c0120b334f8165736c56a"}, + {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e84cc606b1f581733df4350ca4070e6a8b30be3662bbb81a590b177d0c996c91"}, + {file = "dulwich-0.21.7-cp312-cp312-win32.whl", hash = "sha256:c3d1685f320907a52c40fd5890627945c51f3a5fa4bcfe10edb24fec79caadec"}, + {file = "dulwich-0.21.7-cp312-cp312-win_amd64.whl", hash = "sha256:6bd69921fdd813b7469a3c77bc75c1783cc1d8d72ab15a406598e5a3ba1a1503"}, + {file = "dulwich-0.21.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d8ab29c660125db52106775caa1f8f7f77a69ed1fe8bc4b42bdf115731a25bf"}, + {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0d2e4485b98695bf95350ce9d38b1bb0aaac2c34ad00a0df789aa33c934469b"}, + {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e138d516baa6b5bafbe8f030eccc544d0d486d6819b82387fc0e285e62ef5261"}, + {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f34bf9b9fa9308376263fd9ac43143c7c09da9bc75037bb75c6c2423a151b92c"}, + {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e2c66888207b71cd1daa2acb06d3984a6bc13787b837397a64117aa9fc5936a"}, + {file = "dulwich-0.21.7-cp37-cp37m-win32.whl", hash = "sha256:10893105c6566fc95bc2a67b61df7cc1e8f9126d02a1df6a8b2b82eb59db8ab9"}, + {file = "dulwich-0.21.7-cp37-cp37m-win_amd64.whl", hash = "sha256:460b3849d5c3d3818a80743b4f7a0094c893c559f678e56a02fff570b49a644a"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74700e4c7d532877355743336c36f51b414d01e92ba7d304c4f8d9a5946dbc81"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c92e72c43c9e9e936b01a57167e0ea77d3fd2d82416edf9489faa87278a1cdf7"}, + {file = "dulwich-0.21.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d097e963eb6b9fa53266146471531ad9c6765bf390849230311514546ed64db2"}, + {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:808e8b9cc0aa9ac74870b49db4f9f39a52fb61694573f84b9c0613c928d4caf8"}, + {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1957b65f96e36c301e419d7adaadcff47647c30eb072468901bb683b1000bc5"}, + {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4b09bc3a64fb70132ec14326ecbe6e0555381108caff3496898962c4136a48c6"}, + {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5882e70b74ac3c736a42d3fdd4f5f2e6570637f59ad5d3e684760290b58f041"}, + {file = "dulwich-0.21.7-cp38-cp38-win32.whl", hash = "sha256:29bb5c1d70eba155ded41ed8a62be2f72edbb3c77b08f65b89c03976292f6d1b"}, + {file = "dulwich-0.21.7-cp38-cp38-win_amd64.whl", hash = "sha256:25c3ab8fb2e201ad2031ddd32e4c68b7c03cb34b24a5ff477b7a7dcef86372f5"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8929c37986c83deb4eb500c766ee28b6670285b512402647ee02a857320e377c"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc1e11be527ac06316539b57a7688bcb1b6a3e53933bc2f844397bc50734e9ae"}, + {file = "dulwich-0.21.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fc3078a1ba04c588fabb0969d3530efd5cd1ce2cf248eefb6baf7cbc15fc285"}, + {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dcbd29ba30ba2c5bfbab07a61a5f20095541d5ac66d813056c122244df4ac0"}, + {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8869fc8ec3dda743e03d06d698ad489b3705775fe62825e00fa95aa158097fc0"}, + {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d96ca5e0dde49376fbcb44f10eddb6c30284a87bd03bb577c59bb0a1f63903fa"}, + {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0064363bd5e814359657ae32517fa8001e8573d9d040bd997908d488ab886ed"}, + {file = "dulwich-0.21.7-cp39-cp39-win32.whl", hash = "sha256:869eb7be48243e695673b07905d18b73d1054a85e1f6e298fe63ba2843bb2ca1"}, + {file = "dulwich-0.21.7-cp39-cp39-win_amd64.whl", hash = "sha256:404b8edeb3c3a86c47c0a498699fc064c93fa1f8bab2ffe919e8ab03eafaaad3"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e598d743c6c0548ebcd2baf94aa9c8bfacb787ea671eeeb5828cfbd7d56b552f"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a2d76c96426e791556836ef43542b639def81be4f1d6d4322cd886c115eae1"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6c88acb60a1f4d31bd6d13bfba465853b3df940ee4a0f2a3d6c7a0778c705b7"}, + {file = "dulwich-0.21.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ecd315847dea406a4decfa39d388a2521e4e31acde3bd9c2609c989e817c6d62"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d05d3c781bc74e2c2a2a8f4e4e2ed693540fbe88e6ac36df81deac574a6dad99"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6de6f8de4a453fdbae8062a6faa652255d22a3d8bce0cd6d2d6701305c75f2b3"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e25953c7acbbe4e19650d0225af1c0c0e6882f8bddd2056f75c1cc2b109b88ad"}, + {file = "dulwich-0.21.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4637cbd8ed1012f67e1068aaed19fcc8b649bcf3e9e26649826a303298c89b9d"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:858842b30ad6486aacaa607d60bab9c9a29e7c59dc2d9cb77ae5a94053878c08"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:739b191f61e1c4ce18ac7d520e7a7cbda00e182c3489552408237200ce8411ad"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:274c18ec3599a92a9b67abaf110e4f181a4f779ee1aaab9e23a72e89d71b2bd9"}, + {file = "dulwich-0.21.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2590e9b431efa94fc356ae33b38f5e64f1834ec3a94a6ac3a64283b206d07aa3"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed60d1f610ef6437586f7768254c2a93820ccbd4cfdac7d182cf2d6e615969bb"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8278835e168dd097089f9e53088c7a69c6ca0841aef580d9603eafe9aea8c358"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc27fb063f740712e02b4d2f826aee8bbed737ed799962fef625e2ce56e2d29"}, + {file = "dulwich-0.21.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:61e3451bd3d3844f2dca53f131982553be4d1b1e1ebd9db701843dd76c4dba31"}, + {file = "dulwich-0.21.7.tar.gz", hash = "sha256:a9e9c66833cea580c3ac12927e4b9711985d76afca98da971405d414de60e968"}, ] [package.dependencies] @@ -816,13 +840,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.2" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, - {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -830,27 +854,27 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "1.2.0" +version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"}, - {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"}, + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, ] [package.extras] -tests = ["asttokens", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] [[package]] name = "fastjsonschema" -version = "2.18.0" +version = "2.20.0" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.18.0-py3-none-any.whl", hash = "sha256:128039912a11a807068a7c87d0da36660afbfd7202780db26c4aa7153cfdc799"}, - {file = "fastjsonschema-2.18.0.tar.gz", hash = "sha256:e820349dd16f806e4bd1467a138dced9def4bc7d6213a34295272a6cac95b5bd"}, + {file = "fastjsonschema-2.20.0-py3-none-any.whl", hash = "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a"}, + {file = "fastjsonschema-2.20.0.tar.gz", hash = "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23"}, ] [package.extras] @@ -858,18 +882,19 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.12.2" +version = "3.15.4" description = "A platform independent file lock." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, + {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "flake8" @@ -941,17 +966,17 @@ test = ["coverage", "coveralls", "mock", "pytest", "pytest-cov"] [[package]] name = "flake8-comprehensions" -version = "3.14.0" +version = "3.15.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." optional = false python-versions = ">=3.8" files = [ - {file = "flake8_comprehensions-3.14.0-py3-none-any.whl", hash = "sha256:7b9d07d94aa88e62099a6d1931ddf16c344d4157deedf90fe0d8ee2846f30e97"}, - {file = "flake8_comprehensions-3.14.0.tar.gz", hash = "sha256:81768c61bfc064e1a06222df08a2580d97de10cb388694becaf987c331c6c0cf"}, + {file = "flake8_comprehensions-3.15.0-py3-none-any.whl", hash = "sha256:b7e027bbb52be2ceb779ee12484cdeef52b0ad3c1fcb8846292bdb86d3034681"}, + {file = "flake8_comprehensions-3.15.0.tar.gz", hash = "sha256:923c22603e0310376a6b55b03efebdc09753c69f2d977755cba8bb73458a5d4d"}, ] [package.dependencies] -flake8 = ">=3.0,<3.2.0 || >3.2.0" +flake8 = ">=3,<3.2 || >3.2" [[package]] name = "flake8-docstrings" @@ -1093,70 +1118,78 @@ docs = ["alabaster", "myst-parser (>=0.18.0,<0.19.0)", "pygments-github-lexers", [[package]] name = "fonttools" -version = "4.41.1" +version = "4.53.1" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.41.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a7bbb290d13c6dd718ec2c3db46fe6c5f6811e7ea1e07f145fd8468176398224"}, - {file = "fonttools-4.41.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec453a45778524f925a8f20fd26a3326f398bfc55d534e37bab470c5e415caa1"}, - {file = "fonttools-4.41.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2071267deaa6d93cb16288613419679c77220543551cbe61da02c93d92df72f"}, - {file = "fonttools-4.41.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e3334d51f0e37e2c6056e67141b2adabc92613a968797e2571ca8a03bd64773"}, - {file = "fonttools-4.41.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cac73bbef7734e78c60949da11c4903ee5837168e58772371bd42a75872f4f82"}, - {file = "fonttools-4.41.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:edee0900cf0eedb29d17c7876102d6e5a91ee333882b1f5abc83e85b934cadb5"}, - {file = "fonttools-4.41.1-cp310-cp310-win32.whl", hash = "sha256:2a22b2c425c698dcd5d6b0ff0b566e8e9663172118db6fd5f1941f9b8063da9b"}, - {file = "fonttools-4.41.1-cp310-cp310-win_amd64.whl", hash = "sha256:547ab36a799dded58a46fa647266c24d0ed43a66028cd1cd4370b246ad426cac"}, - {file = "fonttools-4.41.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:849ec722bbf7d3501a0e879e57dec1fc54919d31bff3f690af30bb87970f9784"}, - {file = "fonttools-4.41.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38cdecd8f1fd4bf4daae7fed1b3170dfc1b523388d6664b2204b351820aa78a7"}, - {file = "fonttools-4.41.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ae64303ba670f8959fdaaa30ba0c2dabe75364fdec1caeee596c45d51ca3425"}, - {file = "fonttools-4.41.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f14f3ccea4cc7dd1b277385adf3c3bf18f9860f87eab9c2fb650b0af16800f55"}, - {file = "fonttools-4.41.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:33191f062549e6bb1a4782c22a04ebd37009c09360e2d6686ac5083774d06d95"}, - {file = "fonttools-4.41.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:704bccd69b0abb6fab9f5e4d2b75896afa48b427caa2c7988792a2ffce35b441"}, - {file = "fonttools-4.41.1-cp311-cp311-win32.whl", hash = "sha256:4edc795533421e98f60acee7d28fc8d941ff5ac10f44668c9c3635ad72ae9045"}, - {file = "fonttools-4.41.1-cp311-cp311-win_amd64.whl", hash = "sha256:aaaef294d8e411f0ecb778a0aefd11bb5884c9b8333cc1011bdaf3b58ca4bd75"}, - {file = "fonttools-4.41.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3d1f9471134affc1e3b1b806db6e3e2ad3fa99439e332f1881a474c825101096"}, - {file = "fonttools-4.41.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:59eba8b2e749a1de85760da22333f3d17c42b66e03758855a12a2a542723c6e7"}, - {file = "fonttools-4.41.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9b3cc10dc9e0834b6665fd63ae0c6964c6bc3d7166e9bc84772e0edd09f9fa2"}, - {file = "fonttools-4.41.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2c2964bdc827ba6b8a91dc6de792620be4da3922c4cf0599f36a488c07e2b2"}, - {file = "fonttools-4.41.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7763316111df7b5165529f4183a334aa24c13cdb5375ffa1dc8ce309c8bf4e5c"}, - {file = "fonttools-4.41.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b2d1ee95be42b80d1f002d1ee0a51d7a435ea90d36f1a5ae331be9962ee5a3f1"}, - {file = "fonttools-4.41.1-cp38-cp38-win32.whl", hash = "sha256:f48602c0b3fd79cd83a34c40af565fe6db7ac9085c8823b552e6e751e3a5b8be"}, - {file = "fonttools-4.41.1-cp38-cp38-win_amd64.whl", hash = "sha256:b0938ebbeccf7c80bb9a15e31645cf831572c3a33d5cc69abe436e7000c61b14"}, - {file = "fonttools-4.41.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e5c2b0a95a221838991e2f0e455dec1ca3a8cc9cd54febd68cc64d40fdb83669"}, - {file = "fonttools-4.41.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:891cfc5a83b0307688f78b9bb446f03a7a1ad981690ac8362f50518bc6153975"}, - {file = "fonttools-4.41.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73ef0bb5d60eb02ba4d3a7d23ada32184bd86007cb2de3657cfcb1175325fc83"}, - {file = "fonttools-4.41.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f240d9adf0583ac8fc1646afe7f4ac039022b6f8fa4f1575a2cfa53675360b69"}, - {file = "fonttools-4.41.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bdd729744ae7ecd7f7311ad25d99da4999003dcfe43b436cf3c333d4e68de73d"}, - {file = "fonttools-4.41.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b927e5f466d99c03e6e20961946314b81d6e3490d95865ef88061144d9f62e38"}, - {file = "fonttools-4.41.1-cp39-cp39-win32.whl", hash = "sha256:afce2aeb80be72b4da7dd114f10f04873ff512793d13ce0b19d12b2a4c44c0f0"}, - {file = "fonttools-4.41.1-cp39-cp39-win_amd64.whl", hash = "sha256:1df1b6f4c7c4bc8201eb47f3b268adbf2539943aa43c400f84556557e3e109c0"}, - {file = "fonttools-4.41.1-py3-none-any.whl", hash = "sha256:952cb405f78734cf6466252fec42e206450d1a6715746013f64df9cbd4f896fa"}, - {file = "fonttools-4.41.1.tar.gz", hash = "sha256:e16a9449f21a93909c5be2f5ed5246420f2316e94195dbfccb5238aaa38f9751"}, -] - -[package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] + {file = "fonttools-4.53.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397"}, + {file = "fonttools-4.53.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3"}, + {file = "fonttools-4.53.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d"}, + {file = "fonttools-4.53.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0"}, + {file = "fonttools-4.53.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41"}, + {file = "fonttools-4.53.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f"}, + {file = "fonttools-4.53.1-cp310-cp310-win32.whl", hash = "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4"}, + {file = "fonttools-4.53.1-cp310-cp310-win_amd64.whl", hash = "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2"}, + {file = "fonttools-4.53.1-cp311-cp311-win32.whl", hash = "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88"}, + {file = "fonttools-4.53.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f"}, + {file = "fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670"}, + {file = "fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab"}, + {file = "fonttools-4.53.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749"}, + {file = "fonttools-4.53.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2"}, + {file = "fonttools-4.53.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb"}, + {file = "fonttools-4.53.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f"}, + {file = "fonttools-4.53.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d"}, + {file = "fonttools-4.53.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169"}, + {file = "fonttools-4.53.1-cp38-cp38-win32.whl", hash = "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d"}, + {file = "fonttools-4.53.1-cp38-cp38-win_amd64.whl", hash = "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8"}, + {file = "fonttools-4.53.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a"}, + {file = "fonttools-4.53.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31"}, + {file = "fonttools-4.53.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c"}, + {file = "fonttools-4.53.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407"}, + {file = "fonttools-4.53.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb"}, + {file = "fonttools-4.53.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122"}, + {file = "fonttools-4.53.1-cp39-cp39-win32.whl", hash = "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb"}, + {file = "fonttools-4.53.1-cp39-cp39-win_amd64.whl", hash = "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb"}, + {file = "fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d"}, + {file = "fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["munkres", "scipy"] -lxml = ["lxml (>=4.0,<5)"] +interpolatable = ["munkres", "pycairo", "scipy"] +lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.0.0)"] +unicode = ["unicodedata2 (>=15.1.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "gitdb" -version = "4.0.10" +version = "4.0.11" description = "Git Object Database" optional = false python-versions = ">=3.7" files = [ - {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, - {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, ] [package.dependencies] @@ -1164,51 +1197,31 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.37" +version = "3.1.43" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" files = [ - {file = "GitPython-3.1.37-py3-none-any.whl", hash = "sha256:5f4c4187de49616d710a77e98ddf17b4782060a1788df441846bddefbb89ab33"}, - {file = "GitPython-3.1.37.tar.gz", hash = "sha256:f9b9ddc0761c125d5780eab2d64be4873fc6817c2899cbcb34b02344bdc7bc54"}, + {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, + {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, ] [package.dependencies] gitdb = ">=4.0.1,<5" [package.extras] -test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-sugar"] - -[[package]] -name = "html5lib" -version = "1.1" -description = "HTML parser based on the WHATWG HTML specification" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"}, - {file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"}, -] - -[package.dependencies] -six = ">=1.9" -webencodings = "*" - -[package.extras] -all = ["chardet (>=2.2)", "genshi", "lxml"] -chardet = ["chardet (>=2.2)"] -genshi = ["genshi"] -lxml = ["lxml"] +doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] [[package]] name = "idna" -version = "3.4" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -1224,40 +1237,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "8.2.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, + {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] - -[[package]] -name = "importlib-resources" -version = "6.0.0" -description = "Read resources from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_resources-6.0.0-py3-none-any.whl", hash = "sha256:d952faee11004c045f785bb5636e8f885bed30dc3c940d5d42798a2a4541c185"}, - {file = "importlib_resources-6.0.0.tar.gz", hash = "sha256:4cf94875a8368bd89531a756df9a9ebe1f150e0f885030b461237bc7f2d905f2"}, -] - -[package.dependencies] -zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -1283,13 +1278,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.24.0" +version = "6.29.5" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.24.0-py3-none-any.whl", hash = "sha256:2f5fffc7ad8f1fd5aadb4e171ba9129d9668dbafa374732cf9511ada52d6547f"}, - {file = "ipykernel-6.24.0.tar.gz", hash = "sha256:29cea0a716b1176d002a61d0b0c851f34536495bc4ef7dd0222c88b41b816123"}, + {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"}, + {file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"}, ] [package.dependencies] @@ -1303,7 +1298,7 @@ matplotlib-inline = ">=0.1" nest-asyncio = "*" packaging = "*" psutil = "*" -pyzmq = ">=20" +pyzmq = ">=24" tornado = ">=6.1" traitlets = ">=5.4.0" @@ -1312,73 +1307,69 @@ cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] pyqt5 = ["pyqt5"] pyside6 = ["pyside6"] -test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov", "pytest-timeout"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] [[package]] name = "ipython" -version = "8.12.2" +version = "8.26.0" description = "IPython: Productive Interactive Computing" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "ipython-8.12.2-py3-none-any.whl", hash = "sha256:ea8801f15dfe4ffb76dea1b09b847430ffd70d827b41735c64a0638a04103bfc"}, - {file = "ipython-8.12.2.tar.gz", hash = "sha256:c7b80eb7f5a855a88efc971fda506ff7a91c280b42cdae26643e0f601ea281ea"}, + {file = "ipython-8.26.0-py3-none-any.whl", hash = "sha256:e6b347c27bdf9c32ee9d31ae85defc525755a1869f14057e900675b9e8d6e6ff"}, + {file = "ipython-8.26.0.tar.gz", hash = "sha256:1cec0fbba8404af13facebe83d04436a7434c7400e59f47acf467c64abd0956c"}, ] [package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" -prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" -traitlets = ">=5" -typing-extensions = {version = "*", markers = "python_version < \"3.10\""} +traitlets = ">=5.13.0" +typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} [package.extras] -all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] black = ["black"] -doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "intersphinx-registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing-extensions"] kernel = ["ipykernel"] +matplotlib = ["matplotlib"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] [[package]] name = "isort" -version = "5.12.0" +version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, ] [package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] +colors = ["colorama (>=0.4.6)"] [[package]] name = "jaraco-classes" -version = "3.3.0" +version = "3.4.0" description = "Utility functions for Python class constructs" optional = false python-versions = ">=3.8" files = [ - {file = "jaraco.classes-3.3.0-py3-none-any.whl", hash = "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb"}, - {file = "jaraco.classes-3.3.0.tar.gz", hash = "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621"}, + {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, + {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, ] [package.dependencies] @@ -1386,26 +1377,26 @@ more-itertools = "*" [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [[package]] name = "jedi" -version = "0.18.2" +version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." optional = false python-versions = ">=3.6" files = [ - {file = "jedi-0.18.2-py2.py3-none-any.whl", hash = "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e"}, - {file = "jedi-0.18.2.tar.gz", hash = "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612"}, + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, ] [package.dependencies] -parso = ">=0.8.0,<0.9.0" +parso = ">=0.8.3,<0.9.0" [package.extras] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] [[package]] name = "jeepney" @@ -1424,13 +1415,13 @@ trio = ["async_generator", "trio"] [[package]] name = "jinja2" -version = "3.0.3" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, - {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -1441,66 +1432,62 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "joblib" -version = "1.3.2" +version = "1.4.2" description = "Lightweight pipelining with Python functions" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "joblib-1.3.2-py3-none-any.whl", hash = "sha256:ef4331c65f239985f3f2220ecc87db222f08fd22097a3dd5698f693875f8cbb9"}, - {file = "joblib-1.3.2.tar.gz", hash = "sha256:92f865e621e17784e7955080b6d042489e3b8e294949cc44c6eac304f59772b1"}, + {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, + {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, ] [[package]] name = "jsonschema" -version = "4.18.4" +version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.18.4-py3-none-any.whl", hash = "sha256:971be834317c22daaa9132340a51c01b50910724082c2c1a2ac87eeec153a3fe"}, - {file = "jsonschema-4.18.4.tar.gz", hash = "sha256:fb3642735399fa958c0d2aad7057901554596c63349f4f6b283c493cf692a25d"}, + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, ] [package.dependencies] attrs = ">=22.2.0" -importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} jsonschema-specifications = ">=2023.03.6" -pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""} referencing = ">=0.28.4" rpds-py = ">=0.7.1" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-specifications" -version = "2023.7.1" +version = "2023.12.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema_specifications-2023.7.1-py3-none-any.whl", hash = "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1"}, - {file = "jsonschema_specifications-2023.7.1.tar.gz", hash = "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"}, + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, ] [package.dependencies] -importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} -referencing = ">=0.28.0" +referencing = ">=0.31.0" [[package]] name = "jupyter-client" -version = "8.3.0" +version = "8.6.2" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.3.0-py3-none-any.whl", hash = "sha256:7441af0c0672edc5d28035e92ba5e32fadcfa8a4e608a434c228836a89df6158"}, - {file = "jupyter_client-8.3.0.tar.gz", hash = "sha256:3af69921fe99617be1670399a0b857ad67275eefcfa291e2c81a160b7b650f5f"}, + {file = "jupyter_client-8.6.2-py3-none-any.whl", hash = "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f"}, + {file = "jupyter_client-8.6.2.tar.gz", hash = "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df"}, ] [package.dependencies] -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" python-dateutil = ">=2.8.2" pyzmq = ">=23.0" @@ -1509,17 +1496,17 @@ traitlets = ">=5.3" [package.extras] docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] [[package]] name = "jupyter-core" -version = "5.3.1" +version = "5.7.2" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.3.1-py3-none-any.whl", hash = "sha256:ae9036db959a71ec1cac33081eeb040a79e681f08ab68b0883e9a676c7a90dce"}, - {file = "jupyter_core-5.3.1.tar.gz", hash = "sha256:5ba5c7938a7f97a6b0481463f7ff0dbac7c15ba48cf46fa4035ca6e838aa1aba"}, + {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, + {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, ] [package.dependencies] @@ -1528,119 +1515,154 @@ pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_ traitlets = ">=5.3" [package.extras] -docs = ["myst-parser", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] -test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] [[package]] name = "jupyterlab-pygments" -version = "0.2.2" +version = "0.3.0" description = "Pygments theme using JupyterLab CSS variables" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "jupyterlab_pygments-0.2.2-py2.py3-none-any.whl", hash = "sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f"}, - {file = "jupyterlab_pygments-0.2.2.tar.gz", hash = "sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d"}, + {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, + {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, ] [[package]] name = "keyring" -version = "23.13.1" +version = "24.3.1" description = "Store and access your passwords safely." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "keyring-23.13.1-py3-none-any.whl", hash = "sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd"}, - {file = "keyring-23.13.1.tar.gz", hash = "sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678"}, + {file = "keyring-24.3.1-py3-none-any.whl", hash = "sha256:df38a4d7419a6a60fea5cef1e45a948a3e8430dd12ad88b0f423c5c143906218"}, + {file = "keyring-24.3.1.tar.gz", hash = "sha256:c3327b6ffafc0e8befbdb597cacdb4928ffe5c1212f7645f186e6d9957a898db"}, ] [package.dependencies] importlib-metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} -importlib-resources = {version = "*", markers = "python_version < \"3.9\""} "jaraco.classes" = "*" jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} [package.extras] -completion = ["shtab"] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +completion = ["shtab (>=1.1.0)"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [[package]] name = "kiwisolver" -version = "1.4.4" +version = "1.4.5" description = "A fast implementation of the Cassowary constraint solver" optional = false python-versions = ">=3.7" files = [ - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, - {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, ] [[package]] @@ -1654,157 +1676,136 @@ files = [ {file = "linecache2-1.0.0.tar.gz", hash = "sha256:4b26ff4e7110db76eeb6f5a7b64a82623839d595c2038eeda662f2a2db78e97c"}, ] -[[package]] -name = "lockfile" -version = "0.12.2" -description = "Platform-independent file locking module" -optional = false -python-versions = "*" -files = [ - {file = "lockfile-0.12.2-py2.py3-none-any.whl", hash = "sha256:6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa"}, - {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, -] - [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] name = "matplotlib" -version = "3.7.2" +version = "3.9.1" description = "Python plotting package" optional = false -python-versions = ">=3.8" -files = [ - {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"}, - {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"}, - {file = "matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"}, - {file = "matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"}, - {file = "matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"}, - {file = "matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"}, - {file = "matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"}, - {file = "matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"}, - {file = "matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"}, - {file = "matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"}, - {file = "matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"}, - {file = "matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"}, +python-versions = ">=3.9" +files = [ + {file = "matplotlib-3.9.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ccd6270066feb9a9d8e0705aa027f1ff39f354c72a87efe8fa07632f30fc6bb"}, + {file = "matplotlib-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:591d3a88903a30a6d23b040c1e44d1afdd0d778758d07110eb7596f811f31842"}, + {file = "matplotlib-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd2a59ff4b83d33bca3b5ec58203cc65985367812cb8c257f3e101632be86d92"}, + {file = "matplotlib-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc001516ffcf1a221beb51198b194d9230199d6842c540108e4ce109ac05cc0"}, + {file = "matplotlib-3.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:83c6a792f1465d174c86d06f3ae85a8fe36e6f5964633ae8106312ec0921fdf5"}, + {file = "matplotlib-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:421851f4f57350bcf0811edd754a708d2275533e84f52f6760b740766c6747a7"}, + {file = "matplotlib-3.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b3fce58971b465e01b5c538f9d44915640c20ec5ff31346e963c9e1cd66fa812"}, + {file = "matplotlib-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a973c53ad0668c53e0ed76b27d2eeeae8799836fd0d0caaa4ecc66bf4e6676c0"}, + {file = "matplotlib-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd5acf8f3ef43f7532c2f230249720f5dc5dd40ecafaf1c60ac8200d46d7eb"}, + {file = "matplotlib-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab38a4f3772523179b2f772103d8030215b318fef6360cb40558f585bf3d017f"}, + {file = "matplotlib-3.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2315837485ca6188a4b632c5199900e28d33b481eb083663f6a44cfc8987ded3"}, + {file = "matplotlib-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a0c977c5c382f6696caf0bd277ef4f936da7e2aa202ff66cad5f0ac1428ee15b"}, + {file = "matplotlib-3.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:565d572efea2b94f264dd86ef27919515aa6d629252a169b42ce5f570db7f37b"}, + {file = "matplotlib-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d397fd8ccc64af2ec0af1f0efc3bacd745ebfb9d507f3f552e8adb689ed730a"}, + {file = "matplotlib-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26040c8f5121cd1ad712abffcd4b5222a8aec3a0fe40bc8542c94331deb8780d"}, + {file = "matplotlib-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12cb1837cffaac087ad6b44399d5e22b78c729de3cdae4629e252067b705e2b"}, + {file = "matplotlib-3.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0e835c6988edc3d2d08794f73c323cc62483e13df0194719ecb0723b564e0b5c"}, + {file = "matplotlib-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:44a21d922f78ce40435cb35b43dd7d573cf2a30138d5c4b709d19f00e3907fd7"}, + {file = "matplotlib-3.9.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0c584210c755ae921283d21d01f03a49ef46d1afa184134dd0f95b0202ee6f03"}, + {file = "matplotlib-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11fed08f34fa682c2b792942f8902e7aefeed400da71f9e5816bea40a7ce28fe"}, + {file = "matplotlib-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0000354e32efcfd86bda75729716b92f5c2edd5b947200be9881f0a671565c33"}, + {file = "matplotlib-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db17fea0ae3aceb8e9ac69c7e3051bae0b3d083bfec932240f9bf5d0197a049"}, + {file = "matplotlib-3.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:208cbce658b72bf6a8e675058fbbf59f67814057ae78165d8a2f87c45b48d0ff"}, + {file = "matplotlib-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:dc23f48ab630474264276be156d0d7710ac6c5a09648ccdf49fef9200d8cbe80"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3fda72d4d472e2ccd1be0e9ccb6bf0d2eaf635e7f8f51d737ed7e465ac020cb3"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:84b3ba8429935a444f1fdc80ed930babbe06725bcf09fbeb5c8757a2cd74af04"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b918770bf3e07845408716e5bbda17eadfc3fcbd9307dc67f37d6cf834bb3d98"}, + {file = "matplotlib-3.9.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f1f2e5d29e9435c97ad4c36fb6668e89aee13d48c75893e25cef064675038ac9"}, + {file = "matplotlib-3.9.1.tar.gz", hash = "sha256:de06b19b8db95dd33d0dc17c926c7c9ebed9f572074b6fac4f65068a6814d010"}, ] [package.dependencies] contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" -importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} -kiwisolver = ">=1.0.1" -numpy = ">=1.20" +kiwisolver = ">=1.3.1" +numpy = ">=1.23" packaging = ">=20.0" -pillow = ">=6.2.0" -pyparsing = ">=2.3.1,<3.1" +pillow = ">=8" +pyparsing = ">=2.3.1" python-dateutil = ">=2.7" +[package.extras] +dev = ["meson-python (>=0.13.1)", "numpy (>=1.25)", "pybind11 (>=2.6)", "setuptools (>=64)", "setuptools_scm (>=7)"] + [[package]] name = "matplotlib-inline" -version = "0.1.6" +version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, ] [package.dependencies] @@ -1834,96 +1835,89 @@ files = [ [[package]] name = "more-itertools" -version = "10.0.0" +version = "10.3.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.8" files = [ - {file = "more-itertools-10.0.0.tar.gz", hash = "sha256:cd65437d7c4b615ab81c0640c0480bc29a550ea032891977681efd28344d51e1"}, - {file = "more_itertools-10.0.0-py3-none-any.whl", hash = "sha256:928d514ffd22b5b0a8fce326d57f423a55d2ff783b093bab217eda71e732330f"}, + {file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"}, + {file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"}, ] [[package]] name = "msgpack" -version = "1.0.5" +version = "1.0.8" description = "MessagePack serializer" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9"}, - {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198"}, - {file = "msgpack-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81"}, - {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7"}, - {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3"}, - {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b"}, - {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c"}, - {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd"}, - {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a"}, - {file = "msgpack-1.0.5-cp310-cp310-win32.whl", hash = "sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea"}, - {file = "msgpack-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a"}, - {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0"}, - {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898"}, - {file = "msgpack-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a"}, - {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a"}, - {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705"}, - {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d"}, - {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9"}, - {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7"}, - {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed"}, - {file = "msgpack-1.0.5-cp311-cp311-win32.whl", hash = "sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c"}, - {file = "msgpack-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2"}, - {file = "msgpack-1.0.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a2b031c2e9b9af485d5e3c4520f4220d74f4d222a5b8dc8c1a3ab9448ca79c57"}, - {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f837b93669ce4336e24d08286c38761132bc7ab29782727f8557e1eb21b2080"}, - {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1d46dfe3832660f53b13b925d4e0fa1432b00f5f7210eb3ad3bb9a13c6204a6"}, - {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:366c9a7b9057e1547f4ad51d8facad8b406bab69c7d72c0eb6f529cf76d4b85f"}, - {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4c075728a1095efd0634a7dccb06204919a2f67d1893b6aa8e00497258bf926c"}, - {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b"}, - {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:36961b0568c36027c76e2ae3ca1132e35123dcec0706c4b7992683cc26c1320c"}, - {file = "msgpack-1.0.5-cp36-cp36m-win32.whl", hash = "sha256:b5ef2f015b95f912c2fcab19c36814963b5463f1fb9049846994b007962743e9"}, - {file = "msgpack-1.0.5-cp36-cp36m-win_amd64.whl", hash = "sha256:288e32b47e67f7b171f86b030e527e302c91bd3f40fd9033483f2cacc37f327a"}, - {file = "msgpack-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c"}, - {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b"}, - {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f"}, - {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f"}, - {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d"}, - {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086"}, - {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf"}, - {file = "msgpack-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77"}, - {file = "msgpack-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82"}, - {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c"}, - {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d"}, - {file = "msgpack-1.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb"}, - {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba"}, - {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1"}, - {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87"}, - {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb"}, - {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48"}, - {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0"}, - {file = "msgpack-1.0.5-cp38-cp38-win32.whl", hash = "sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e"}, - {file = "msgpack-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1"}, - {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025"}, - {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5"}, - {file = "msgpack-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd"}, - {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437"}, - {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f"}, - {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282"}, - {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d"}, - {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8"}, - {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11"}, - {file = "msgpack-1.0.5-cp39-cp39-win32.whl", hash = "sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc"}, - {file = "msgpack-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164"}, - {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, + {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, + {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, + {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, + {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, + {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, + {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, + {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, + {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, + {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, + {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, + {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] [[package]] name = "nbclient" -version = "0.8.0" +version = "0.10.0" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false python-versions = ">=3.8.0" files = [ - {file = "nbclient-0.8.0-py3-none-any.whl", hash = "sha256:25e861299e5303a0477568557c4045eccc7a34c17fc08e7959558707b9ebe548"}, - {file = "nbclient-0.8.0.tar.gz", hash = "sha256:f9b179cd4b2d7bca965f900a2ebf0db4a12ebff2f36a711cb66861e4ae158e55"}, + {file = "nbclient-0.10.0-py3-none-any.whl", hash = "sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f"}, + {file = "nbclient-0.10.0.tar.gz", hash = "sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09"}, ] [package.dependencies] @@ -1935,7 +1929,7 @@ traitlets = ">=5.4" [package.extras] dev = ["pre-commit"] docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] -test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] [[package]] name = "nbconvert" @@ -1952,7 +1946,6 @@ files = [ beautifulsoup4 = "*" bleach = "*" defusedxml = "*" -importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} jinja2 = ">=3.0" jupyter-core = ">=4.7" jupyterlab-pygments = "*" @@ -1977,19 +1970,19 @@ webpdf = ["pyppeteer (>=1,<1.1)"] [[package]] name = "nbformat" -version = "5.9.1" +version = "5.10.4" description = "The Jupyter Notebook format" optional = false python-versions = ">=3.8" files = [ - {file = "nbformat-5.9.1-py3-none-any.whl", hash = "sha256:b7968ebf4811178a4108ee837eae1442e3f054132100f0359219e9ed1ce3ca45"}, - {file = "nbformat-5.9.1.tar.gz", hash = "sha256:3a7f52d040639cbd8a3890218c8b0ffb93211588c57446c90095e32ba5881b5d"}, + {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, + {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, ] [package.dependencies] -fastjsonschema = "*" +fastjsonschema = ">=2.15" jsonschema = ">=2.6" -jupyter-core = "*" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" traitlets = ">=5.1" [package.extras] @@ -1998,13 +1991,13 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] [[package]] name = "nest-asyncio" -version = "1.5.6" +version = "1.6.0" description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" files = [ - {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"}, - {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, ] [[package]] @@ -2027,50 +2020,58 @@ test = ["codecov (>=2.1)", "pytest (>=7.1)", "pytest-cov (>=3.0)"] [[package]] name = "numpy" -version = "1.24.4" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false -python-versions = ">=3.8" -files = [ - {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, - {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, - {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, - {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, - {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, - {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, - {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, - {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, - {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, - {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, - {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, - {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, - {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, - {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, - {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, - {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, - {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, - {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, - {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, - {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, - {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, - {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, - {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, - {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, - {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, - {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] name = "packaging" -version = "23.1" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -2110,10 +2111,7 @@ files = [ ] [package.dependencies] -numpy = [ - {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, -] +numpy = {version = ">=1.21.0", markers = "python_version >= \"3.10\""} python-dateutil = ">=2.8.1" pytz = ">=2020.1" @@ -2122,39 +2120,39 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] [[package]] name = "pandocfilters" -version = "1.5.0" +version = "1.5.1" description = "Utilities for writing pandoc filters in python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"}, - {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"}, + {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, + {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, ] [[package]] name = "parso" -version = "0.8.3" +version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, ] [package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] [[package]] name = "pbr" -version = "5.11.1" +version = "6.0.0" description = "Python Build Reasonableness" optional = false python-versions = ">=2.6" files = [ - {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"}, - {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"}, + {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"}, + {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"}, ] [[package]] @@ -2174,145 +2172,154 @@ flake8-polyfill = ">=1.0.2,<2" [[package]] name = "pexpect" -version = "4.8.0" +version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" files = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, ] [package.dependencies] ptyprocess = ">=0.5" -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -optional = false -python-versions = "*" -files = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] - [[package]] name = "pillow" -version = "10.0.1" +version = "10.4.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "Pillow-10.0.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:8f06be50669087250f319b706decf69ca71fdecd829091a37cc89398ca4dc17a"}, - {file = "Pillow-10.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50bd5f1ebafe9362ad622072a1d2f5850ecfa44303531ff14353a4059113b12d"}, - {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6a90167bcca1216606223a05e2cf991bb25b14695c518bc65639463d7db722d"}, - {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f11c9102c56ffb9ca87134bd025a43d2aba3f1155f508eff88f694b33a9c6d19"}, - {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:186f7e04248103482ea6354af6d5bcedb62941ee08f7f788a1c7707bc720c66f"}, - {file = "Pillow-10.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0462b1496505a3462d0f35dc1c4d7b54069747d65d00ef48e736acda2c8cbdff"}, - {file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d889b53ae2f030f756e61a7bff13684dcd77e9af8b10c6048fb2c559d6ed6eaf"}, - {file = "Pillow-10.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:552912dbca585b74d75279a7570dd29fa43b6d93594abb494ebb31ac19ace6bd"}, - {file = "Pillow-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:787bb0169d2385a798888e1122c980c6eff26bf941a8ea79747d35d8f9210ca0"}, - {file = "Pillow-10.0.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fd2a5403a75b54661182b75ec6132437a181209b901446ee5724b589af8edef1"}, - {file = "Pillow-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2d7e91b4379f7a76b31c2dda84ab9e20c6220488e50f7822e59dac36b0cd92b1"}, - {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19e9adb3f22d4c416e7cd79b01375b17159d6990003633ff1d8377e21b7f1b21"}, - {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93139acd8109edcdeffd85e3af8ae7d88b258b3a1e13a038f542b79b6d255c54"}, - {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:92a23b0431941a33242b1f0ce6c88a952e09feeea9af4e8be48236a68ffe2205"}, - {file = "Pillow-10.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cbe68deb8580462ca0d9eb56a81912f59eb4542e1ef8f987405e35a0179f4ea2"}, - {file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:522ff4ac3aaf839242c6f4e5b406634bfea002469656ae8358644fc6c4856a3b"}, - {file = "Pillow-10.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:84efb46e8d881bb06b35d1d541aa87f574b58e87f781cbba8d200daa835b42e1"}, - {file = "Pillow-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:898f1d306298ff40dc1b9ca24824f0488f6f039bc0e25cfb549d3195ffa17088"}, - {file = "Pillow-10.0.1-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:bcf1207e2f2385a576832af02702de104be71301c2696d0012b1b93fe34aaa5b"}, - {file = "Pillow-10.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d6c9049c6274c1bb565021367431ad04481ebb54872edecfcd6088d27edd6ed"}, - {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28444cb6ad49726127d6b340217f0627abc8732f1194fd5352dec5e6a0105635"}, - {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de596695a75496deb3b499c8c4f8e60376e0516e1a774e7bc046f0f48cd620ad"}, - {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2872f2d7846cf39b3dbff64bc1104cc48c76145854256451d33c5faa55c04d1a"}, - {file = "Pillow-10.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4ce90f8a24e1c15465048959f1e94309dfef93af272633e8f37361b824532e91"}, - {file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ee7810cf7c83fa227ba9125de6084e5e8b08c59038a7b2c9045ef4dde61663b4"}, - {file = "Pillow-10.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1be1c872b9b5fcc229adeadbeb51422a9633abd847c0ff87dc4ef9bb184ae08"}, - {file = "Pillow-10.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:98533fd7fa764e5f85eebe56c8e4094db912ccbe6fbf3a58778d543cadd0db08"}, - {file = "Pillow-10.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:764d2c0daf9c4d40ad12fbc0abd5da3af7f8aa11daf87e4fa1b834000f4b6b0a"}, - {file = "Pillow-10.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fcb59711009b0168d6ee0bd8fb5eb259c4ab1717b2f538bbf36bacf207ef7a68"}, - {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:697a06bdcedd473b35e50a7e7506b1d8ceb832dc238a336bd6f4f5aa91a4b500"}, - {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f665d1e6474af9f9da5e86c2a3a2d2d6204e04d5af9c06b9d42afa6ebde3f21"}, - {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:2fa6dd2661838c66f1a5473f3b49ab610c98a128fc08afbe81b91a1f0bf8c51d"}, - {file = "Pillow-10.0.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:3a04359f308ebee571a3127fdb1bd01f88ba6f6fb6d087f8dd2e0d9bff43f2a7"}, - {file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:723bd25051454cea9990203405fa6b74e043ea76d4968166dfd2569b0210886a"}, - {file = "Pillow-10.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:71671503e3015da1b50bd18951e2f9daf5b6ffe36d16f1eb2c45711a301521a7"}, - {file = "Pillow-10.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:44e7e4587392953e5e251190a964675f61e4dae88d1e6edbe9f36d6243547ff3"}, - {file = "Pillow-10.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:3855447d98cced8670aaa63683808df905e956f00348732448b5a6df67ee5849"}, - {file = "Pillow-10.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ed2d9c0704f2dc4fa980b99d565c0c9a543fe5101c25b3d60488b8ba80f0cce1"}, - {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5bb289bb835f9fe1a1e9300d011eef4d69661bb9b34d5e196e5e82c4cb09b37"}, - {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0d3e54ab1df9df51b914b2233cf779a5a10dfd1ce339d0421748232cea9876"}, - {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:2cc6b86ece42a11f16f55fe8903595eff2b25e0358dec635d0a701ac9586588f"}, - {file = "Pillow-10.0.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ca26ba5767888c84bf5a0c1a32f069e8204ce8c21d00a49c90dabeba00ce0145"}, - {file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f0b4b06da13275bc02adfeb82643c4a6385bd08d26f03068c2796f60d125f6f2"}, - {file = "Pillow-10.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bc2e3069569ea9dbe88d6b8ea38f439a6aad8f6e7a6283a38edf61ddefb3a9bf"}, - {file = "Pillow-10.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:8b451d6ead6e3500b6ce5c7916a43d8d8d25ad74b9102a629baccc0808c54971"}, - {file = "Pillow-10.0.1-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:32bec7423cdf25c9038fef614a853c9d25c07590e1a870ed471f47fb80b244db"}, - {file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cf63d2c6928b51d35dfdbda6f2c1fddbe51a6bc4a9d4ee6ea0e11670dd981e"}, - {file = "Pillow-10.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f6d3d4c905e26354e8f9d82548475c46d8e0889538cb0657aa9c6f0872a37aa4"}, - {file = "Pillow-10.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:847e8d1017c741c735d3cd1883fa7b03ded4f825a6e5fcb9378fd813edee995f"}, - {file = "Pillow-10.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:7f771e7219ff04b79e231d099c0a28ed83aa82af91fd5fa9fdb28f5b8d5addaf"}, - {file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459307cacdd4138edee3875bbe22a2492519e060660eaf378ba3b405d1c66317"}, - {file = "Pillow-10.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b059ac2c4c7a97daafa7dc850b43b2d3667def858a4f112d1aa082e5c3d6cf7d"}, - {file = "Pillow-10.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6caf3cd38449ec3cd8a68b375e0c6fe4b6fd04edb6c9766b55ef84a6e8ddf2d"}, - {file = "Pillow-10.0.1.tar.gz", hash = "sha256:d72967b06be9300fed5cfbc8b5bafceec48bf7cdc7dab66b1d2549035287191d"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] + {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, + {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, + {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, + {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, + {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, + {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, + {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, + {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, + {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, + {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, + {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, + {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, + {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, + {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, + {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, + {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, + {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, + {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "pkginfo" -version = "1.9.6" +version = "1.11.1" description = "Query metadata from sdists / bdists / installed packages." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pkginfo-1.9.6-py3-none-any.whl", hash = "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546"}, - {file = "pkginfo-1.9.6.tar.gz", hash = "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046"}, + {file = "pkginfo-1.11.1-py3-none-any.whl", hash = "sha256:bfa76a714fdfc18a045fcd684dbfc3816b603d9d075febef17cb6582bea29573"}, + {file = "pkginfo-1.11.1.tar.gz", hash = "sha256:2e0dca1cf4c8e39644eed32408ea9966ee15e0d324c62ba899a393b3c6b467aa"}, ] [package.extras] -testing = ["pytest", "pytest-cov"] - -[[package]] -name = "pkgutil-resolve-name" -version = "1.3.10" -description = "Resolve a name to an object." -optional = false -python-versions = ">=3.6" -files = [ - {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, - {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, -] +testing = ["pytest", "pytest-cov", "wheel"] [[package]] name = "platformdirs" -version = "3.9.1" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-3.9.1-py3-none-any.whl", hash = "sha256:ad8291ae0ae5072f66c16945166cb11c63394c7a3ad1b1bc9828ca3162da8c2f"}, - {file = "platformdirs-3.9.1.tar.gz", hash = "sha256:1b42b450ad933e981d56e59f1b97495428c9bd60698baab9f3eb3d00d5822421"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] [[package]] name = "pluggy" -version = "1.2.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -2321,80 +2328,75 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "poetry" -version = "1.5.1" +version = "1.8.3" description = "Python dependency management and packaging made easy." optional = false -python-versions = ">=3.7,<4.0" +python-versions = "<4.0,>=3.8" files = [ - {file = "poetry-1.5.1-py3-none-any.whl", hash = "sha256:dfc7ce3a38ae216c0465694e2e674bef6eb1a2ba81aa47a26f9dc03362fe2f5f"}, - {file = "poetry-1.5.1.tar.gz", hash = "sha256:cc7ea4524d1a11558006224bfe8ba8ed071417d4eb5ef6c89decc6a37d437eeb"}, + {file = "poetry-1.8.3-py3-none-any.whl", hash = "sha256:88191c69b08d06f9db671b793d68f40048e8904c0718404b63dcc2b5aec62d13"}, + {file = "poetry-1.8.3.tar.gz", hash = "sha256:67f4eb68288eab41e841cc71a00d26cf6bdda9533022d0189a145a34d0a35f48"}, ] [package.dependencies] -build = ">=0.10.0,<0.11.0" -cachecontrol = {version = ">=0.12.9,<0.13.0", extras = ["filecache"]} -cleo = ">=2.0.0,<3.0.0" +build = ">=1.0.3,<2.0.0" +cachecontrol = {version = ">=0.14.0,<0.15.0", extras = ["filecache"]} +cleo = ">=2.1.0,<3.0.0" crashtest = ">=0.4.1,<0.5.0" dulwich = ">=0.21.2,<0.22.0" -filelock = ">=3.8.0,<4.0.0" -html5lib = ">=1.0,<2.0" -importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} +fastjsonschema = ">=2.18.0,<3.0.0" installer = ">=0.7.0,<0.8.0" -jsonschema = ">=4.10.0,<5.0.0" -keyring = ">=23.9.0,<24.0.0" -lockfile = ">=0.12.2,<0.13.0" -packaging = ">=20.4" +keyring = ">=24.0.0,<25.0.0" +packaging = ">=23.1" pexpect = ">=4.7.0,<5.0.0" -pkginfo = ">=1.9.4,<2.0.0" -platformdirs = ">=3.0.0,<4.0.0" -poetry-core = "1.6.1" -poetry-plugin-export = ">=1.4.0,<2.0.0" +pkginfo = ">=1.10,<2.0" +platformdirs = ">=3.0.0,<5" +poetry-core = "1.9.0" +poetry-plugin-export = ">=1.6.0,<2.0.0" pyproject-hooks = ">=1.0.0,<2.0.0" -requests = ">=2.18,<3.0" -requests-toolbelt = ">=0.9.1,<2" +requests = ">=2.26,<3.0" +requests-toolbelt = ">=1.0.0,<2.0.0" shellingham = ">=1.5,<2.0" tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.11.4,<1.0.0" trove-classifiers = ">=2022.5.19" -urllib3 = ">=1.26.0,<2.0.0" -virtualenv = ">=20.22.0,<21.0.0" -xattr = {version = ">=0.10.0,<0.11.0", markers = "sys_platform == \"darwin\""} +virtualenv = ">=20.23.0,<21.0.0" +xattr = {version = ">=1.0.0,<2.0.0", markers = "sys_platform == \"darwin\""} [[package]] name = "poetry-core" -version = "1.6.1" +version = "1.9.0" description = "Poetry PEP 517 Build Backend" optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.8,<4.0" files = [ - {file = "poetry_core-1.6.1-py3-none-any.whl", hash = "sha256:70707340447dee0e7f334f9495ae652481c67b32d8d218f296a376ac2ed73573"}, - {file = "poetry_core-1.6.1.tar.gz", hash = "sha256:0f9b0de39665f36d6594657e7d57b6f463cc10f30c28e6d1c3b9ff54c26c9ac3"}, + {file = "poetry_core-1.9.0-py3-none-any.whl", hash = "sha256:4e0c9c6ad8cf89956f03b308736d84ea6ddb44089d16f2adc94050108ec1f5a1"}, + {file = "poetry_core-1.9.0.tar.gz", hash = "sha256:fa7a4001eae8aa572ee84f35feb510b321bd652e5cf9293249d62853e1f935a2"}, ] [[package]] name = "poetry-plugin-export" -version = "1.4.0" +version = "1.8.0" description = "Poetry plugin to export the dependencies to various formats" optional = false -python-versions = ">=3.7,<4.0" +python-versions = "<4.0,>=3.8" files = [ - {file = "poetry_plugin_export-1.4.0-py3-none-any.whl", hash = "sha256:5d9186d6f77cf2bf35fc96bd11fe650cc7656e515b17d99cb65018d50ba22589"}, - {file = "poetry_plugin_export-1.4.0.tar.gz", hash = "sha256:f16974cd9f222d4ef640fa97a8d661b04d4fb339e51da93973f1bc9d578e183f"}, + {file = "poetry_plugin_export-1.8.0-py3-none-any.whl", hash = "sha256:adbe232cfa0cc04991ea3680c865cf748bff27593b9abcb1f35fb50ed7ba2c22"}, + {file = "poetry_plugin_export-1.8.0.tar.gz", hash = "sha256:1fa6168a85d59395d835ca564bc19862a7c76061e60c3e7dfaec70d50937fc61"}, ] [package.dependencies] -poetry = ">=1.5.0,<2.0.0" -poetry-core = ">=1.6.0,<2.0.0" +poetry = ">=1.8.0,<3.0.0" +poetry-core = ">=1.7.0,<3.0.0" [[package]] name = "prompt-toolkit" -version = "3.0.39" +version = "3.0.47" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, + {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, + {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, ] [package.dependencies] @@ -2402,25 +2404,28 @@ wcwidth = "*" [[package]] name = "psutil" -version = "5.9.5" +version = "6.0.0" description = "Cross-platform lib for process and system monitoring in Python." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, - {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, - {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, - {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, - {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, - {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, - {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, - {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, - {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, - {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, - {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, - {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, - {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, - {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, + {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c"}, + {file = "psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35"}, + {file = "psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1"}, + {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, + {file = "psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14"}, + {file = "psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c"}, + {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, + {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, + {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, + {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, ] [package.extras] @@ -2439,13 +2444,13 @@ files = [ [[package]] name = "pure-eval" -version = "0.2.2" +version = "0.2.3" description = "Safely evaluate AST nodes without side effects" optional = false python-versions = "*" files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, ] [package.extras] @@ -2464,13 +2469,13 @@ files = [ [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] @@ -2503,27 +2508,27 @@ files = [ [[package]] name = "pygments" -version = "2.15.1" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, - {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyparsing" -version = "3.0.9" +version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -2531,27 +2536,24 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pyproject-hooks" -version = "1.0.0" +version = "1.1.0" description = "Wrappers to call pyproject.toml-based build backend hooks." optional = false python-versions = ">=3.7" files = [ - {file = "pyproject_hooks-1.0.0-py3-none-any.whl", hash = "sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8"}, - {file = "pyproject_hooks-1.0.0.tar.gz", hash = "sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5"}, + {file = "pyproject_hooks-1.1.0-py3-none-any.whl", hash = "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2"}, + {file = "pyproject_hooks-1.1.0.tar.gz", hash = "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965"}, ] -[package.dependencies] -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} - [[package]] name = "pytest" -version = "7.4.0" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -2585,13 +2587,13 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -2599,13 +2601,13 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2023.3" +version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, - {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -2654,7 +2656,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -2662,15 +2663,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -2687,7 +2681,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -2695,7 +2688,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -2703,88 +2695,99 @@ files = [ [[package]] name = "pyzmq" -version = "25.1.0" +version = "26.0.3" description = "Python bindings for 0MQ" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pyzmq-25.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:1a6169e69034eaa06823da6a93a7739ff38716142b3596c180363dee729d713d"}, - {file = "pyzmq-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:19d0383b1f18411d137d891cab567de9afa609b214de68b86e20173dc624c101"}, - {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1e931d9a92f628858a50f5bdffdfcf839aebe388b82f9d2ccd5d22a38a789dc"}, - {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97d984b1b2f574bc1bb58296d3c0b64b10e95e7026f8716ed6c0b86d4679843f"}, - {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:154bddda2a351161474b36dba03bf1463377ec226a13458725183e508840df89"}, - {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cb6d161ae94fb35bb518b74bb06b7293299c15ba3bc099dccd6a5b7ae589aee3"}, - {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:90146ab578931e0e2826ee39d0c948d0ea72734378f1898939d18bc9c823fcf9"}, - {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:831ba20b660b39e39e5ac8603e8193f8fce1ee03a42c84ade89c36a251449d80"}, - {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a522510e3434e12aff80187144c6df556bb06fe6b9d01b2ecfbd2b5bfa5c60c"}, - {file = "pyzmq-25.1.0-cp310-cp310-win32.whl", hash = "sha256:be24a5867b8e3b9dd5c241de359a9a5217698ff616ac2daa47713ba2ebe30ad1"}, - {file = "pyzmq-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:5693dcc4f163481cf79e98cf2d7995c60e43809e325b77a7748d8024b1b7bcba"}, - {file = "pyzmq-25.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:13bbe36da3f8aaf2b7ec12696253c0bf6ffe05f4507985a8844a1081db6ec22d"}, - {file = "pyzmq-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:69511d604368f3dc58d4be1b0bad99b61ee92b44afe1cd9b7bd8c5e34ea8248a"}, - {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a983c8694667fd76d793ada77fd36c8317e76aa66eec75be2653cef2ea72883"}, - {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:332616f95eb400492103ab9d542b69d5f0ff628b23129a4bc0a2fd48da6e4e0b"}, - {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58416db767787aedbfd57116714aad6c9ce57215ffa1c3758a52403f7c68cff5"}, - {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cad9545f5801a125f162d09ec9b724b7ad9b6440151b89645241d0120e119dcc"}, - {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d6128d431b8dfa888bf51c22a04d48bcb3d64431caf02b3cb943269f17fd2994"}, - {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b15247c49d8cbea695b321ae5478d47cffd496a2ec5ef47131a9e79ddd7e46c"}, - {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:442d3efc77ca4d35bee3547a8e08e8d4bb88dadb54a8377014938ba98d2e074a"}, - {file = "pyzmq-25.1.0-cp311-cp311-win32.whl", hash = "sha256:65346f507a815a731092421d0d7d60ed551a80d9b75e8b684307d435a5597425"}, - {file = "pyzmq-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:8b45d722046fea5a5694cba5d86f21f78f0052b40a4bbbbf60128ac55bfcc7b6"}, - {file = "pyzmq-25.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f45808eda8b1d71308c5416ef3abe958f033fdbb356984fabbfc7887bed76b3f"}, - {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b697774ea8273e3c0460cf0bba16cd85ca6c46dfe8b303211816d68c492e132"}, - {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b324fa769577fc2c8f5efcd429cef5acbc17d63fe15ed16d6dcbac2c5eb00849"}, - {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5873d6a60b778848ce23b6c0ac26c39e48969823882f607516b91fb323ce80e5"}, - {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f0d9e7ba6a815a12c8575ba7887da4b72483e4cfc57179af10c9b937f3f9308f"}, - {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:414b8beec76521358b49170db7b9967d6974bdfc3297f47f7d23edec37329b00"}, - {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:01f06f33e12497dca86353c354461f75275a5ad9eaea181ac0dc1662da8074fa"}, - {file = "pyzmq-25.1.0-cp36-cp36m-win32.whl", hash = "sha256:b5a07c4f29bf7cb0164664ef87e4aa25435dcc1f818d29842118b0ac1eb8e2b5"}, - {file = "pyzmq-25.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:968b0c737797c1809ec602e082cb63e9824ff2329275336bb88bd71591e94a90"}, - {file = "pyzmq-25.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:47b915ba666c51391836d7ed9a745926b22c434efa76c119f77bcffa64d2c50c"}, - {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af31493663cf76dd36b00dafbc839e83bbca8a0662931e11816d75f36155897"}, - {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5489738a692bc7ee9a0a7765979c8a572520d616d12d949eaffc6e061b82b4d1"}, - {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1fc56a0221bdf67cfa94ef2d6ce5513a3d209c3dfd21fed4d4e87eca1822e3a3"}, - {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:75217e83faea9edbc29516fc90c817bc40c6b21a5771ecb53e868e45594826b0"}, - {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3830be8826639d801de9053cf86350ed6742c4321ba4236e4b5568528d7bfed7"}, - {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3575699d7fd7c9b2108bc1c6128641a9a825a58577775ada26c02eb29e09c517"}, - {file = "pyzmq-25.1.0-cp37-cp37m-win32.whl", hash = "sha256:95bd3a998d8c68b76679f6b18f520904af5204f089beebb7b0301d97704634dd"}, - {file = "pyzmq-25.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:dbc466744a2db4b7ca05589f21ae1a35066afada2f803f92369f5877c100ef62"}, - {file = "pyzmq-25.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:3bed53f7218490c68f0e82a29c92335daa9606216e51c64f37b48eb78f1281f4"}, - {file = "pyzmq-25.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb52e826d16c09ef87132c6e360e1879c984f19a4f62d8a935345deac43f3c12"}, - {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ddbef8b53cd16467fdbfa92a712eae46dd066aa19780681a2ce266e88fbc7165"}, - {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9301cf1d7fc1ddf668d0abbe3e227fc9ab15bc036a31c247276012abb921b5ff"}, - {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e23a8c3b6c06de40bdb9e06288180d630b562db8ac199e8cc535af81f90e64b"}, - {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4a82faae00d1eed4809c2f18b37f15ce39a10a1c58fe48b60ad02875d6e13d80"}, - {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c8398a1b1951aaa330269c35335ae69744be166e67e0ebd9869bdc09426f3871"}, - {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d40682ac60b2a613d36d8d3a0cd14fbdf8e7e0618fbb40aa9fa7b796c9081584"}, - {file = "pyzmq-25.1.0-cp38-cp38-win32.whl", hash = "sha256:33d5c8391a34d56224bccf74f458d82fc6e24b3213fc68165c98b708c7a69325"}, - {file = "pyzmq-25.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:c66b7ff2527e18554030319b1376d81560ca0742c6e0b17ff1ee96624a5f1afd"}, - {file = "pyzmq-25.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:af56229ea6527a849ac9fb154a059d7e32e77a8cba27e3e62a1e38d8808cb1a5"}, - {file = "pyzmq-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bdca18b94c404af6ae5533cd1bc310c4931f7ac97c148bbfd2cd4bdd62b96253"}, - {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0b6b42f7055bbc562f63f3df3b63e3dd1ebe9727ff0f124c3aa7bcea7b3a00f9"}, - {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c2fc7aad520a97d64ffc98190fce6b64152bde57a10c704b337082679e74f67"}, - {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be86a26415a8b6af02cd8d782e3a9ae3872140a057f1cadf0133de685185c02b"}, - {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:851fb2fe14036cfc1960d806628b80276af5424db09fe5c91c726890c8e6d943"}, - {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2a21fec5c3cea45421a19ccbe6250c82f97af4175bc09de4d6dd78fb0cb4c200"}, - {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bad172aba822444b32eae54c2d5ab18cd7dee9814fd5c7ed026603b8cae2d05f"}, - {file = "pyzmq-25.1.0-cp39-cp39-win32.whl", hash = "sha256:4d67609b37204acad3d566bb7391e0ecc25ef8bae22ff72ebe2ad7ffb7847158"}, - {file = "pyzmq-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:71c7b5896e40720d30cd77a81e62b433b981005bbff0cb2f739e0f8d059b5d99"}, - {file = "pyzmq-25.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cb27ef9d3bdc0c195b2dc54fcb8720e18b741624686a81942e14c8b67cc61a6"}, - {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0c4fc2741e0513b5d5a12fe200d6785bbcc621f6f2278893a9ca7bed7f2efb7d"}, - {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fc34fdd458ff77a2a00e3c86f899911f6f269d393ca5675842a6e92eea565bae"}, - {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8751f9c1442624da391bbd92bd4b072def6d7702a9390e4479f45c182392ff78"}, - {file = "pyzmq-25.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:6581e886aec3135964a302a0f5eb68f964869b9efd1dbafdebceaaf2934f8a68"}, - {file = "pyzmq-25.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5482f08d2c3c42b920e8771ae8932fbaa0a67dff925fc476996ddd8155a170f3"}, - {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7fbcafa3ea16d1de1f213c226005fea21ee16ed56134b75b2dede5a2129e62"}, - {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:adecf6d02b1beab8d7c04bc36f22bb0e4c65a35eb0b4750b91693631d4081c70"}, - {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6d39e42a0aa888122d1beb8ec0d4ddfb6c6b45aecb5ba4013c27e2f28657765"}, - {file = "pyzmq-25.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7018289b402ebf2b2c06992813523de61d4ce17bd514c4339d8f27a6f6809492"}, - {file = "pyzmq-25.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9e68ae9864d260b18f311b68d29134d8776d82e7f5d75ce898b40a88df9db30f"}, - {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e21cc00e4debe8f54c3ed7b9fcca540f46eee12762a9fa56feb8512fd9057161"}, - {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f666ae327a6899ff560d741681fdcdf4506f990595201ed39b44278c471ad98"}, - {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f5efcc29056dfe95e9c9db0dfbb12b62db9c4ad302f812931b6d21dd04a9119"}, - {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:48e5e59e77c1a83162ab3c163fc01cd2eebc5b34560341a67421b09be0891287"}, - {file = "pyzmq-25.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:108c96ebbd573d929740d66e4c3d1bdf31d5cde003b8dc7811a3c8c5b0fc173b"}, - {file = "pyzmq-25.1.0.tar.gz", hash = "sha256:80c41023465d36280e801564a69cbfce8ae85ff79b080e1913f6e90481fb8957"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, + {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, + {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, + {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, + {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, + {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, + {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, + {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, ] [package.dependencies] @@ -2792,103 +2795,104 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "rapidfuzz" -version = "2.15.1" +version = "3.9.4" description = "rapid fuzzy string matching" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "rapidfuzz-2.15.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fc0bc259ebe3b93e7ce9df50b3d00e7345335d35acbd735163b7c4b1957074d3"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d59fb3a410d253f50099d7063855c2b95df1ef20ad93ea3a6b84115590899f25"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c525a3da17b6d79d61613096c8683da86e3573e807dfaecf422eea09e82b5ba6"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4deae6a918ecc260d0c4612257be8ba321d8e913ccb43155403842758c46fbe"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2577463d10811386e704a3ab58b903eb4e2a31b24dfd9886d789b0084d614b01"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f67d5f56aa48c0da9de4ab81bffb310683cf7815f05ea38e5aa64f3ba4368339"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7927722ff43690e52b3145b5bd3089151d841d350c6f8378c3cfac91f67573a"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6534afc787e32c4104f65cdeb55f6abe4d803a2d0553221d00ef9ce12788dcde"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d0ae6ec79a1931929bb9dd57bc173eb5ba4c7197461bf69e3a34b6dd314feed2"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be7ccc45c4d1a7dfb595f260e8022a90c6cb380c2a346ee5aae93f85c96d362b"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:8ba013500a2b68c64b2aecc5fb56a2dad6c2872cf545a0308fd044827b6e5f6a"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4d9f7d10065f657f960b48699e7dddfce14ab91af4bab37a215f0722daf0d716"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7e24a1b802cea04160b3fccd75d2d0905065783ebc9de157d83c14fb9e1c6ce2"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-win32.whl", hash = "sha256:dffdf03499e0a5b3442951bb82b556333b069e0661e80568752786c79c5b32de"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d150d90a7c6caae7962f29f857a4e61d42038cfd82c9df38508daf30c648ae7"}, - {file = "rapidfuzz-2.15.1-cp310-cp310-win_arm64.whl", hash = "sha256:87c30e9184998ff6eb0fa9221f94282ce7c908fd0da96a1ef66ecadfaaa4cdb7"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6986413cb37035eb796e32f049cbc8c13d8630a4ac1e0484e3e268bb3662bd1b"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a72f26e010d4774b676f36e43c0fc8a2c26659efef4b3be3fd7714d3491e9957"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b5cd54c98a387cca111b3b784fc97a4f141244bbc28a92d4bde53f164464112e"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da7fac7c3da39f93e6b2ebe386ed0ffe1cefec91509b91857f6e1204509e931f"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f976e76ac72f650790b3a5402431612175b2ac0363179446285cb3c901136ca9"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:abde47e1595902a490ed14d4338d21c3509156abb2042a99e6da51f928e0c117"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca8f1747007a3ce919739a60fa95c5325f7667cccf6f1c1ef18ae799af119f5e"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c35da09ab9797b020d0d4f07a66871dfc70ea6566363811090353ea971748b5a"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a3a769ca7580686a66046b77df33851b3c2d796dc1eb60c269b68f690f3e1b65"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d50622efefdb03a640a51a6123748cd151d305c1f0431af762e833d6ffef71f0"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b7461b0a7651d68bc23f0896bffceea40f62887e5ab8397bf7caa883592ef5cb"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:074ee9e17912e025c72a5780ee4c7c413ea35cd26449719cc399b852d4e42533"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7025fb105a11f503943f17718cdb8241ea3bb4d812c710c609e69bead40e2ff0"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-win32.whl", hash = "sha256:2084d36b95139413cef25e9487257a1cc892b93bd1481acd2a9656f7a1d9930c"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:5a738fcd24e34bce4b19126b92fdae15482d6d3a90bd687fd3d24ce9d28ce82d"}, - {file = "rapidfuzz-2.15.1-cp311-cp311-win_arm64.whl", hash = "sha256:dc3cafa68cfa54638632bdcadf9aab89a3d182b4a3f04d2cad7585ed58ea8731"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3c53d57ba7a88f7bf304d4ea5a14a0ca112db0e0178fff745d9005acf2879f7d"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6ee758eec4cf2215dc8d8eafafcea0d1f48ad4b0135767db1b0f7c5c40a17dd"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d93ba3ae59275e7a3a116dac4ffdb05e9598bf3ee0861fecc5b60fb042d539e"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c3ff75e647908ddbe9aa917fbe39a112d5631171f3fcea5809e2363e525a59d"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d89c421702474c6361245b6b199e6e9783febacdbfb6b002669e6cb3ef17a09"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f69e6199fec0f58f9a89afbbaea78d637c7ce77f656a03a1d6ea6abdc1d44f8"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:41dfea282844d0628279b4db2929da0dacb8ac317ddc5dcccc30093cf16357c1"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2dd03477feefeccda07b7659dd614f6738cfc4f9b6779dd61b262a73b0a9a178"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:5efe035aa76ff37d1b5fa661de3c4b4944de9ff227a6c0b2e390a95c101814c0"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ed2cf7c69102c7a0a06926d747ed855bc836f52e8d59a5d1e3adfd980d1bd165"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a0e441d4c2025110ec3eba5d54f11f78183269a10152b3a757a739ffd1bb12bf"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-win32.whl", hash = "sha256:a4a54efe17cc9f53589c748b53f28776dfdfb9bc83619685740cb7c37985ac2f"}, - {file = "rapidfuzz-2.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:bb8318116ecac4dfb84841d8b9b461f9bb0c3be5b616418387d104f72d2a16d1"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e9296c530e544f68858c3416ad1d982a1854f71e9d2d3dcedb5b216e6d54f067"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:49c4bcdb9238f11f8c4eba1b898937f09b92280d6f900023a8216008f299b41a"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebb40a279e134bb3fef099a8b58ed5beefb201033d29bdac005bddcdb004ef71"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7381c11cb590bbd4e6f2d8779a0b34fdd2234dfa13d0211f6aee8ca166d9d05"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfdcdedfd12a0077193f2cf3626ff6722c5a184adf0d2d51f1ec984bf21c23c3"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85bece1ec59bda8b982bd719507d468d4df746dfb1988df11d916b5e9fe19e8"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1b393f4a1eaa6867ffac6aef58cfb04bab2b3d7d8e40b9fe2cf40dd1d384601"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53de456ef020a77bf9d7c6c54860a48e2e902584d55d3001766140ac45c54bc7"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2492330bc38b76ed967eab7bdaea63a89b6ceb254489e2c65c3824efcbf72993"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:099e4c6befaa8957a816bdb67ce664871f10aaec9bebf2f61368cf7e0869a7a1"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:46599b2ad4045dd3f794a24a6db1e753d23304699d4984462cf1ead02a51ddf3"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:591f19d16758a3c55c9d7a0b786b40d95599a5b244d6eaef79c7a74fcf5104d8"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ed17359061840eb249f8d833cb213942e8299ffc4f67251a6ed61833a9f2ea20"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-win32.whl", hash = "sha256:aa1e5aad325168e29bf8e17006479b97024aa9d2fdbe12062bd2f8f09080acf8"}, - {file = "rapidfuzz-2.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:c2bb68832b140c551dbed691290bef4ee6719d4e8ce1b7226a3736f61a9d1a83"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3fac40972cf7b6c14dded88ae2331eb50dfbc278aa9195473ef6fc6bfe49f686"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0e456cbdc0abf39352800309dab82fd3251179fa0ff6573fa117f51f4e84be8"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:22b9d22022b9d09fd4ece15102270ab9b6a5cfea8b6f6d1965c1df7e3783f5ff"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46754fe404a9a6f5cbf7abe02d74af390038d94c9b8c923b3f362467606bfa28"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91abb8bf7610efe326394adc1d45e1baca8f360e74187f3fa0ef3df80cdd3ba6"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e40a2f60024f9d3c15401e668f732800114a023f3f8d8c40f1521a62081ff054"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a48ee83916401ac73938526d7bd804e01d2a8fe61809df7f1577b0b3b31049a3"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71580052f9dbac443c02f60484e5a2e5f72ad4351b84b2009fbe345b1f38422"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:82b86d5b8c1b9bcbc65236d75f81023c78d06a721c3e0229889ff4ed5c858169"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fc4528b7736e5c30bc954022c2cf410889abc19504a023abadbc59cdf9f37cae"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e1e0e569108a5760d8f01d0f2148dd08cc9a39ead79fbefefca9e7c7723c7e88"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:94e1c97f0ad45b05003806f8a13efc1fc78983e52fa2ddb00629003acf4676ef"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47e81767a962e41477a85ad7ac937e34d19a7d2a80be65614f008a5ead671c56"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-win32.whl", hash = "sha256:79fc574aaf2d7c27ec1022e29c9c18f83cdaf790c71c05779528901e0caad89b"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:f3dd4bcef2d600e0aa121e19e6e62f6f06f22a89f82ef62755e205ce14727874"}, - {file = "rapidfuzz-2.15.1-cp39-cp39-win_arm64.whl", hash = "sha256:cac095cbdf44bc286339a77214bbca6d4d228c9ebae3da5ff6a80aaeb7c35634"}, - {file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b89d1126be65c85763d56e3b47d75f1a9b7c5529857b4d572079b9a636eaa8a7"}, - {file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7460e91168229768be882ea365ba0ac7da43e57f9416e2cfadc396a7df3c2"}, - {file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c33c03e7092642c38f8a15ca2d8fc38da366f2526ec3b46adf19d5c7aa48ba"}, - {file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040faca2e26d9dab5541b45ce72b3f6c0e36786234703fc2ac8c6f53bb576743"}, - {file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:6e2a3b23e1e9aa13474b3c710bba770d0dcc34d517d3dd6f97435a32873e3f28"}, - {file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2e597b9dfd6dd180982684840975c458c50d447e46928efe3e0120e4ec6f6686"}, - {file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d14752c9dd2036c5f36ebe8db5f027275fa7d6b3ec6484158f83efb674bab84e"}, - {file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558224b6fc6124d13fa32d57876f626a7d6188ba2a97cbaea33a6ee38a867e31"}, - {file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c89cfa88dc16fd8c9bcc0c7f0b0073f7ef1e27cceb246c9f5a3f7004fa97c4d"}, - {file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:509c5b631cd64df69f0f011893983eb15b8be087a55bad72f3d616b6ae6a0f96"}, - {file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0f73a04135a03a6e40393ecd5d46a7a1049d353fc5c24b82849830d09817991f"}, - {file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c99d53138a2dfe8ada67cb2855719f934af2733d726fbf73247844ce4dd6dd5"}, - {file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f01fa757f0fb332a1f045168d29b0d005de6c39ee5ce5d6c51f2563bb53c601b"}, - {file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60368e1add6e550faae65614844c43f8a96e37bf99404643b648bf2dba92c0fb"}, - {file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:785744f1270828cc632c5a3660409dee9bcaac6931a081bae57542c93e4d46c4"}, - {file = "rapidfuzz-2.15.1.tar.gz", hash = "sha256:d62137c2ca37aea90a11003ad7dc109c8f1739bfbe5a9a217f3cdb07d7ac00f6"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b9793c19bdf38656c8eaefbcf4549d798572dadd70581379e666035c9df781"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:015b5080b999404fe06ec2cb4f40b0be62f0710c926ab41e82dfbc28e80675b4"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acc5ceca9c1e1663f3e6c23fb89a311f69b7615a40ddd7645e3435bf3082688a"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1424e238bc3f20e1759db1e0afb48a988a9ece183724bef91ea2a291c0b92a95"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed01378f605aa1f449bee82cd9c83772883120d6483e90aa6c5a4ce95dc5c3aa"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb26d412271e5a76cdee1c2d6bf9881310665d3fe43b882d0ed24edfcb891a84"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f37e9e1f17be193c41a31c864ad4cd3ebd2b40780db11cd5c04abf2bcf4201b"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d070ec5cf96b927c4dc5133c598c7ff6db3b833b363b2919b13417f1002560bc"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:10e61bb7bc807968cef09a0e32ce253711a2d450a4dce7841d21d45330ffdb24"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:31a2fc60bb2c7face4140010a7aeeafed18b4f9cdfa495cc644a68a8c60d1ff7"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fbebf1791a71a2e89f5c12b78abddc018354d5859e305ec3372fdae14f80a826"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:aee9fc9e3bb488d040afc590c0a7904597bf4ccd50d1491c3f4a5e7e67e6cd2c"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-win32.whl", hash = "sha256:005a02688a51c7d2451a2d41c79d737aa326ff54167211b78a383fc2aace2c2c"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:3a2e75e41ee3274754d3b2163cc6c82cd95b892a85ab031f57112e09da36455f"}, + {file = "rapidfuzz-3.9.4-cp310-cp310-win_arm64.whl", hash = "sha256:2c99d355f37f2b289e978e761f2f8efeedc2b14f4751d9ff7ee344a9a5ca98d9"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:07141aa6099e39d48637ce72a25b893fc1e433c50b3e837c75d8edf99e0c63e1"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:db1664eaff5d7d0f2542dd9c25d272478deaf2c8412e4ad93770e2e2d828e175"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc01a223f6605737bec3202e94dcb1a449b6c76d46082cfc4aa980f2a60fd40e"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1869c42e73e2a8910b479be204fa736418741b63ea2325f9cc583c30f2ded41a"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62ea7007941fb2795fff305ac858f3521ec694c829d5126e8f52a3e92ae75526"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:698e992436bf7f0afc750690c301215a36ff952a6dcd62882ec13b9a1ebf7a39"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b76f611935f15a209d3730c360c56b6df8911a9e81e6a38022efbfb96e433bab"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129627d730db2e11f76169344a032f4e3883d34f20829419916df31d6d1338b1"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:90a82143c14e9a14b723a118c9ef8d1bbc0c5a16b1ac622a1e6c916caff44dd8"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ded58612fe3b0e0d06e935eaeaf5a9fd27da8ba9ed3e2596307f40351923bf72"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f16f5d1c4f02fab18366f2d703391fcdbd87c944ea10736ca1dc3d70d8bd2d8b"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:26aa7eece23e0df55fb75fbc2a8fb678322e07c77d1fd0e9540496e6e2b5f03e"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-win32.whl", hash = "sha256:f187a9c3b940ce1ee324710626daf72c05599946bd6748abe9e289f1daa9a077"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d8e9130fe5d7c9182990b366ad78fd632f744097e753e08ace573877d67c32f8"}, + {file = "rapidfuzz-3.9.4-cp311-cp311-win_arm64.whl", hash = "sha256:40419e98b10cd6a00ce26e4837a67362f658fc3cd7a71bd8bd25c99f7ee8fea5"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b5d5072b548db1b313a07d62d88fe0b037bd2783c16607c647e01b070f6cf9e5"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cf5bcf22e1f0fd273354462631d443ef78d677f7d2fc292de2aec72ae1473e66"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c8fc973adde8ed52810f590410e03fb6f0b541bbaeb04c38d77e63442b2df4c"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2464bb120f135293e9a712e342c43695d3d83168907df05f8c4ead1612310c7"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d9d58689aca22057cf1a5851677b8a3ccc9b535ca008c7ed06dc6e1899f7844"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167e745f98baa0f3034c13583e6302fb69249a01239f1483d68c27abb841e0a1"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db0bf0663b4b6da1507869722420ea9356b6195aa907228d6201303e69837af9"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd6ac61b74fdb9e23f04d5f068e6cf554f47e77228ca28aa2347a6ca8903972f"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:60ff67c690acecf381759c16cb06c878328fe2361ddf77b25d0e434ea48a29da"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:cb934363380c60f3a57d14af94325125cd8cded9822611a9f78220444034e36e"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fe833493fb5cc5682c823ea3e2f7066b07612ee8f61ecdf03e1268f262106cdd"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2797fb847d89e04040d281cb1902cbeffbc4b5131a5c53fc0db490fd76b2a547"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-win32.whl", hash = "sha256:52e3d89377744dae68ed7c84ad0ddd3f5e891c82d48d26423b9e066fc835cc7c"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:c76da20481c906e08400ee9be230f9e611d5931a33707d9df40337c2655c84b5"}, + {file = "rapidfuzz-3.9.4-cp312-cp312-win_arm64.whl", hash = "sha256:f2d2846f3980445864c7e8b8818a29707fcaff2f0261159ef6b7bd27ba139296"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:355fc4a268ffa07bab88d9adee173783ec8d20136059e028d2a9135c623c44e6"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d81a78f90269190b568a8353d4ea86015289c36d7e525cd4d43176c88eff429"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e618625ffc4660b26dc8e56225f8b966d5842fa190e70c60db6cd393e25b86e"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b712336ad6f2bacdbc9f1452556e8942269ef71f60a9e6883ef1726b52d9228a"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc1ee19fdad05770c897e793836c002344524301501d71ef2e832847425707"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1950f8597890c0c707cb7e0416c62a1cf03dcdb0384bc0b2dbda7e05efe738ec"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a6c35f272ec9c430568dc8c1c30cb873f6bc96be2c79795e0bce6db4e0e101d"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:1df0f9e9239132a231c86ae4f545ec2b55409fa44470692fcfb36b1bd00157ad"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:d2c51955329bfccf99ae26f63d5928bf5be9fcfcd9f458f6847fd4b7e2b8986c"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:3c522f462d9fc504f2ea8d82e44aa580e60566acc754422c829ad75c752fbf8d"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:d8a52fc50ded60d81117d7647f262c529659fb21d23e14ebfd0b35efa4f1b83d"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:04dbdfb0f0bfd3f99cf1e9e24fadc6ded2736d7933f32f1151b0f2abb38f9a25"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-win32.whl", hash = "sha256:4968c8bd1df84b42f382549e6226710ad3476f976389839168db3e68fd373298"}, + {file = "rapidfuzz-3.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:3fe4545f89f8d6c27b6bbbabfe40839624873c08bd6700f63ac36970a179f8f5"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9f256c8fb8f3125574c8c0c919ab0a1f75d7cba4d053dda2e762dcc36357969d"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5fdc09cf6e9d8eac3ce48a4615b3a3ee332ea84ac9657dbbefef913b13e632f"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d395d46b80063d3b5d13c0af43d2c2cedf3ab48c6a0c2aeec715aa5455b0c632"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7fa714fb96ce9e70c37e64c83b62fe8307030081a0bfae74a76fac7ba0f91715"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bc1a0f29f9119be7a8d3c720f1d2068317ae532e39e4f7f948607c3a6de8396"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6022674aa1747d6300f699cd7c54d7dae89bfe1f84556de699c4ac5df0838082"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcb72e5f9762fd469701a7e12e94b924af9004954f8c739f925cb19c00862e38"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad04ae301129f0eb5b350a333accd375ce155a0c1cec85ab0ec01f770214e2e4"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f46a22506f17c0433e349f2d1dc11907c393d9b3601b91d4e334fa9a439a6a4d"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:01b42a8728c36011718da409aa86b84984396bf0ca3bfb6e62624f2014f6022c"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e590d5d5443cf56f83a51d3c4867bd1f6be8ef8cfcc44279522bcef3845b2a51"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4c72078b5fdce34ba5753f9299ae304e282420e6455e043ad08e4488ca13a2b0"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-win32.whl", hash = "sha256:f75639277304e9b75e6a7b3c07042d2264e16740a11e449645689ed28e9c2124"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:e81e27e8c32a1e1278a4bb1ce31401bfaa8c2cc697a053b985a6f8d013df83ec"}, + {file = "rapidfuzz-3.9.4-cp39-cp39-win_arm64.whl", hash = "sha256:15bc397ee9a3ed1210b629b9f5f1da809244adc51ce620c504138c6e7095b7bd"}, + {file = "rapidfuzz-3.9.4-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:20488ade4e1ddba3cfad04f400da7a9c1b91eff5b7bd3d1c50b385d78b587f4f"}, + {file = "rapidfuzz-3.9.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e61b03509b1a6eb31bc5582694f6df837d340535da7eba7bedb8ae42a2fcd0b9"}, + {file = "rapidfuzz-3.9.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:098d231d4e51644d421a641f4a5f2f151f856f53c252b03516e01389b2bfef99"}, + {file = "rapidfuzz-3.9.4-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17ab8b7d10fde8dd763ad428aa961c0f30a1b44426e675186af8903b5d134fb0"}, + {file = "rapidfuzz-3.9.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e272df61bee0a056a3daf99f9b1bd82cf73ace7d668894788139c868fdf37d6f"}, + {file = "rapidfuzz-3.9.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d6481e099ff8c4edda85b8b9b5174c200540fd23c8f38120016c765a86fa01f5"}, + {file = "rapidfuzz-3.9.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ad61676e9bdae677d577fe80ec1c2cea1d150c86be647e652551dcfe505b1113"}, + {file = "rapidfuzz-3.9.4-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:af65020c0dd48d0d8ae405e7e69b9d8ae306eb9b6249ca8bf511a13f465fad85"}, + {file = "rapidfuzz-3.9.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d38b4e026fcd580e0bda6c0ae941e0e9a52c6bc66cdce0b8b0da61e1959f5f8"}, + {file = "rapidfuzz-3.9.4-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f74ed072c2b9dc6743fb19994319d443a4330b0e64aeba0aa9105406c7c5b9c2"}, + {file = "rapidfuzz-3.9.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee5f6b8321f90615c184bd8a4c676e9becda69b8e4e451a90923db719d6857c"}, + {file = "rapidfuzz-3.9.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3a555e3c841d6efa350f862204bb0a3fea0c006b8acc9b152b374fa36518a1c6"}, + {file = "rapidfuzz-3.9.4-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0772150d37bf018110351c01d032bf9ab25127b966a29830faa8ad69b7e2f651"}, + {file = "rapidfuzz-3.9.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:addcdd3c3deef1bd54075bd7aba0a6ea9f1d01764a08620074b7a7b1e5447cb9"}, + {file = "rapidfuzz-3.9.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fe86b82b776554add8f900b6af202b74eb5efe8f25acdb8680a5c977608727f"}, + {file = "rapidfuzz-3.9.4-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0fc91ac59f4414d8542454dfd6287a154b8e6f1256718c898f695bdbb993467"}, + {file = "rapidfuzz-3.9.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a944e546a296a5fdcaabb537b01459f1b14d66f74e584cb2a91448bffadc3c1"}, + {file = "rapidfuzz-3.9.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4fb96ba96d58c668a17a06b5b5e8340fedc26188e87b0d229d38104556f30cd8"}, + {file = "rapidfuzz-3.9.4.tar.gz", hash = "sha256:366bf8947b84e37f2f4cf31aaf5f37c39f620d8c0eddb8b633e6ba0129ca4a0a"}, ] [package.extras] @@ -2896,13 +2900,13 @@ full = ["numpy"] [[package]] name = "referencing" -version = "0.30.0" +version = "0.35.1" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.30.0-py3-none-any.whl", hash = "sha256:c257b08a399b6c2f5a3510a50d28ab5dbc7bbde049bcaf954d43c446f83ab548"}, - {file = "referencing-0.30.0.tar.gz", hash = "sha256:47237742e990457f7512c7d27486394a9aadaf876cbfaa4be65b27b4f4d47c6b"}, + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, ] [package.dependencies] @@ -2911,13 +2915,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -2946,194 +2950,202 @@ requests = ">=2.0.1,<3.0.0" [[package]] name = "rpds-py" -version = "0.9.2" +version = "0.19.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.9.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:ab6919a09c055c9b092798ce18c6c4adf49d24d4d9e43a92b257e3f2548231e7"}, - {file = "rpds_py-0.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d55777a80f78dd09410bd84ff8c95ee05519f41113b2df90a69622f5540c4f8b"}, - {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a216b26e5af0a8e265d4efd65d3bcec5fba6b26909014effe20cd302fd1138fa"}, - {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29cd8bfb2d716366a035913ced99188a79b623a3512292963d84d3e06e63b496"}, - {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44659b1f326214950a8204a248ca6199535e73a694be8d3e0e869f820767f12f"}, - {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:745f5a43fdd7d6d25a53ab1a99979e7f8ea419dfefebcab0a5a1e9095490ee5e"}, - {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a987578ac5214f18b99d1f2a3851cba5b09f4a689818a106c23dbad0dfeb760f"}, - {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf4151acb541b6e895354f6ff9ac06995ad9e4175cbc6d30aaed08856558201f"}, - {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:03421628f0dc10a4119d714a17f646e2837126a25ac7a256bdf7c3943400f67f"}, - {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13b602dc3e8dff3063734f02dcf05111e887f301fdda74151a93dbbc249930fe"}, - {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fae5cb554b604b3f9e2c608241b5d8d303e410d7dfb6d397c335f983495ce7f6"}, - {file = "rpds_py-0.9.2-cp310-none-win32.whl", hash = "sha256:47c5f58a8e0c2c920cc7783113df2fc4ff12bf3a411d985012f145e9242a2764"}, - {file = "rpds_py-0.9.2-cp310-none-win_amd64.whl", hash = "sha256:4ea6b73c22d8182dff91155af018b11aac9ff7eca085750455c5990cb1cfae6e"}, - {file = "rpds_py-0.9.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:e564d2238512c5ef5e9d79338ab77f1cbbda6c2d541ad41b2af445fb200385e3"}, - {file = "rpds_py-0.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f411330a6376fb50e5b7a3e66894e4a39e60ca2e17dce258d53768fea06a37bd"}, - {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e7521f5af0233e89939ad626b15278c71b69dc1dfccaa7b97bd4cdf96536bb7"}, - {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d3335c03100a073883857e91db9f2e0ef8a1cf42dc0369cbb9151c149dbbc1b"}, - {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d25b1c1096ef0447355f7293fbe9ad740f7c47ae032c2884113f8e87660d8f6e"}, - {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a5d3fbd02efd9cf6a8ffc2f17b53a33542f6b154e88dd7b42ef4a4c0700fdad"}, - {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5934e2833afeaf36bd1eadb57256239785f5af0220ed8d21c2896ec4d3a765f"}, - {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:095b460e117685867d45548fbd8598a8d9999227e9061ee7f012d9d264e6048d"}, - {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91378d9f4151adc223d584489591dbb79f78814c0734a7c3bfa9c9e09978121c"}, - {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:24a81c177379300220e907e9b864107614b144f6c2a15ed5c3450e19cf536fae"}, - {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:de0b6eceb46141984671802d412568d22c6bacc9b230174f9e55fc72ef4f57de"}, - {file = "rpds_py-0.9.2-cp311-none-win32.whl", hash = "sha256:700375326ed641f3d9d32060a91513ad668bcb7e2cffb18415c399acb25de2ab"}, - {file = "rpds_py-0.9.2-cp311-none-win_amd64.whl", hash = "sha256:0766babfcf941db8607bdaf82569ec38107dbb03c7f0b72604a0b346b6eb3298"}, - {file = "rpds_py-0.9.2-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1440c291db3f98a914e1afd9d6541e8fc60b4c3aab1a9008d03da4651e67386"}, - {file = "rpds_py-0.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0f2996fbac8e0b77fd67102becb9229986396e051f33dbceada3debaacc7033f"}, - {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f30d205755566a25f2ae0382944fcae2f350500ae4df4e795efa9e850821d82"}, - {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:159fba751a1e6b1c69244e23ba6c28f879a8758a3e992ed056d86d74a194a0f3"}, - {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1f044792e1adcea82468a72310c66a7f08728d72a244730d14880cd1dabe36b"}, - {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9251eb8aa82e6cf88510530b29eef4fac825a2b709baf5b94a6094894f252387"}, - {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01899794b654e616c8625b194ddd1e5b51ef5b60ed61baa7a2d9c2ad7b2a4238"}, - {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0c43f8ae8f6be1d605b0465671124aa8d6a0e40f1fb81dcea28b7e3d87ca1e1"}, - {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:207f57c402d1f8712618f737356e4b6f35253b6d20a324d9a47cb9f38ee43a6b"}, - {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b52e7c5ae35b00566d244ffefba0f46bb6bec749a50412acf42b1c3f402e2c90"}, - {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:978fa96dbb005d599ec4fd9ed301b1cc45f1a8f7982d4793faf20b404b56677d"}, - {file = "rpds_py-0.9.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6aa8326a4a608e1c28da191edd7c924dff445251b94653988efb059b16577a4d"}, - {file = "rpds_py-0.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aad51239bee6bff6823bbbdc8ad85136c6125542bbc609e035ab98ca1e32a192"}, - {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd4dc3602370679c2dfb818d9c97b1137d4dd412230cfecd3c66a1bf388a196"}, - {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd9da77c6ec1f258387957b754f0df60766ac23ed698b61941ba9acccd3284d1"}, - {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:190ca6f55042ea4649ed19c9093a9be9d63cd8a97880106747d7147f88a49d18"}, - {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:876bf9ed62323bc7dcfc261dbc5572c996ef26fe6406b0ff985cbcf460fc8a4c"}, - {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa2818759aba55df50592ecbc95ebcdc99917fa7b55cc6796235b04193eb3c55"}, - {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9ea4d00850ef1e917815e59b078ecb338f6a8efda23369677c54a5825dbebb55"}, - {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5855c85eb8b8a968a74dc7fb014c9166a05e7e7a8377fb91d78512900aadd13d"}, - {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:14c408e9d1a80dcb45c05a5149e5961aadb912fff42ca1dd9b68c0044904eb32"}, - {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:65a0583c43d9f22cb2130c7b110e695fff834fd5e832a776a107197e59a1898e"}, - {file = "rpds_py-0.9.2-cp38-none-win32.whl", hash = "sha256:71f2f7715935a61fa3e4ae91d91b67e571aeb5cb5d10331ab681256bda2ad920"}, - {file = "rpds_py-0.9.2-cp38-none-win_amd64.whl", hash = "sha256:674c704605092e3ebbbd13687b09c9f78c362a4bc710343efe37a91457123044"}, - {file = "rpds_py-0.9.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:07e2c54bef6838fa44c48dfbc8234e8e2466d851124b551fc4e07a1cfeb37260"}, - {file = "rpds_py-0.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fdf55283ad38c33e35e2855565361f4bf0abd02470b8ab28d499c663bc5d7c"}, - {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:890ba852c16ace6ed9f90e8670f2c1c178d96510a21b06d2fa12d8783a905193"}, - {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50025635ba8b629a86d9d5474e650da304cb46bbb4d18690532dd79341467846"}, - {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:517cbf6e67ae3623c5127206489d69eb2bdb27239a3c3cc559350ef52a3bbf0b"}, - {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0836d71ca19071090d524739420a61580f3f894618d10b666cf3d9a1688355b1"}, - {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c439fd54b2b9053717cca3de9583be6584b384d88d045f97d409f0ca867d80f"}, - {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f68996a3b3dc9335037f82754f9cdbe3a95db42bde571d8c3be26cc6245f2324"}, - {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7d68dc8acded354c972116f59b5eb2e5864432948e098c19fe6994926d8e15c3"}, - {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f963c6b1218b96db85fc37a9f0851eaf8b9040aa46dec112611697a7023da535"}, - {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a46859d7f947061b4010e554ccd1791467d1b1759f2dc2ec9055fa239f1bc26"}, - {file = "rpds_py-0.9.2-cp39-none-win32.whl", hash = "sha256:e07e5dbf8a83c66783a9fe2d4566968ea8c161199680e8ad38d53e075df5f0d0"}, - {file = "rpds_py-0.9.2-cp39-none-win_amd64.whl", hash = "sha256:682726178138ea45a0766907957b60f3a1bf3acdf212436be9733f28b6c5af3c"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:196cb208825a8b9c8fc360dc0f87993b8b260038615230242bf18ec84447c08d"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c7671d45530fcb6d5e22fd40c97e1e1e01965fc298cbda523bb640f3d923b387"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83b32f0940adec65099f3b1c215ef7f1d025d13ff947975a055989cb7fd019a4"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f67da97f5b9eac838b6980fc6da268622e91f8960e083a34533ca710bec8611"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03975db5f103997904c37e804e5f340c8fdabbb5883f26ee50a255d664eed58c"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:987b06d1cdb28f88a42e4fb8a87f094e43f3c435ed8e486533aea0bf2e53d931"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c861a7e4aef15ff91233751619ce3a3d2b9e5877e0fcd76f9ea4f6847183aa16"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02938432352359805b6da099c9c95c8a0547fe4b274ce8f1a91677401bb9a45f"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef1f08f2a924837e112cba2953e15aacfccbbfcd773b4b9b4723f8f2ddded08e"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:35da5cc5cb37c04c4ee03128ad59b8c3941a1e5cd398d78c37f716f32a9b7f67"}, - {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:141acb9d4ccc04e704e5992d35472f78c35af047fa0cfae2923835d153f091be"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79f594919d2c1a0cc17d1988a6adaf9a2f000d2e1048f71f298b056b1018e872"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:a06418fe1155e72e16dddc68bb3780ae44cebb2912fbd8bb6ff9161de56e1798"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b2eb034c94b0b96d5eddb290b7b5198460e2d5d0c421751713953a9c4e47d10"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b08605d248b974eb02f40bdcd1a35d3924c83a2a5e8f5d0fa5af852c4d960af"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0805911caedfe2736935250be5008b261f10a729a303f676d3d5fea6900c96a"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab2299e3f92aa5417d5e16bb45bb4586171c1327568f638e8453c9f8d9e0f020"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c8d7594e38cf98d8a7df25b440f684b510cf4627fe038c297a87496d10a174f"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b9ec12ad5f0a4625db34db7e0005be2632c1013b253a4a60e8302ad4d462afd"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1fcdee18fea97238ed17ab6478c66b2095e4ae7177e35fb71fbe561a27adf620"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:933a7d5cd4b84f959aedeb84f2030f0a01d63ae6cf256629af3081cf3e3426e8"}, - {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:686ba516e02db6d6f8c279d1641f7067ebb5dc58b1d0536c4aaebb7bf01cdc5d"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0173c0444bec0a3d7d848eaeca2d8bd32a1b43f3d3fde6617aac3731fa4be05f"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d576c3ef8c7b2d560e301eb33891d1944d965a4d7a2eacb6332eee8a71827db6"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed89861ee8c8c47d6beb742a602f912b1bb64f598b1e2f3d758948721d44d468"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1054a08e818f8e18910f1bee731583fe8f899b0a0a5044c6e680ceea34f93876"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e7c4bb27ff1aab90dcc3e9d37ee5af0231ed98d99cb6f5250de28889a3d502"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c545d9d14d47be716495076b659db179206e3fd997769bc01e2d550eeb685596"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9039a11bca3c41be5a58282ed81ae422fa680409022b996032a43badef2a3752"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fb39aca7a64ad0c9490adfa719dbeeb87d13be137ca189d2564e596f8ba32c07"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2d8b3b3a2ce0eaa00c5bbbb60b6713e94e7e0becab7b3db6c5c77f979e8ed1f1"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:99b1c16f732b3a9971406fbfe18468592c5a3529585a45a35adbc1389a529a03"}, - {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c27ee01a6c3223025f4badd533bea5e87c988cb0ba2811b690395dfe16088cfe"}, - {file = "rpds_py-0.9.2.tar.gz", hash = "sha256:8d70e8f14900f2657c249ea4def963bed86a29b81f81f5b76b5a9215680de945"}, + {file = "rpds_py-0.19.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:aaf71f95b21f9dc708123335df22e5a2fef6307e3e6f9ed773b2e0938cc4d491"}, + {file = "rpds_py-0.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca0dda0c5715efe2ab35bb83f813f681ebcd2840d8b1b92bfc6fe3ab382fae4a"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81db2e7282cc0487f500d4db203edc57da81acde9e35f061d69ed983228ffe3b"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1a8dfa125b60ec00c7c9baef945bb04abf8ac772d8ebefd79dae2a5f316d7850"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:271accf41b02687cef26367c775ab220372ee0f4925591c6796e7c148c50cab5"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9bc4161bd3b970cd6a6fcda70583ad4afd10f2750609fb1f3ca9505050d4ef3"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0cf2a0dbb5987da4bd92a7ca727eadb225581dd9681365beba9accbe5308f7d"}, + {file = "rpds_py-0.19.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b5e28e56143750808c1c79c70a16519e9bc0a68b623197b96292b21b62d6055c"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c7af6f7b80f687b33a4cdb0a785a5d4de1fb027a44c9a049d8eb67d5bfe8a687"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e429fc517a1c5e2a70d576077231538a98d59a45dfc552d1ac45a132844e6dfb"}, + {file = "rpds_py-0.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d2dbd8f4990d4788cb122f63bf000357533f34860d269c1a8e90ae362090ff3a"}, + {file = "rpds_py-0.19.1-cp310-none-win32.whl", hash = "sha256:e0f9d268b19e8f61bf42a1da48276bcd05f7ab5560311f541d22557f8227b866"}, + {file = "rpds_py-0.19.1-cp310-none-win_amd64.whl", hash = "sha256:df7c841813f6265e636fe548a49664c77af31ddfa0085515326342a751a6ba51"}, + {file = "rpds_py-0.19.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:902cf4739458852fe917104365ec0efbea7d29a15e4276c96a8d33e6ed8ec137"}, + {file = "rpds_py-0.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f3d73022990ab0c8b172cce57c69fd9a89c24fd473a5e79cbce92df87e3d9c48"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3837c63dd6918a24de6c526277910e3766d8c2b1627c500b155f3eecad8fad65"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cdb7eb3cf3deb3dd9e7b8749323b5d970052711f9e1e9f36364163627f96da58"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26ab43b6d65d25b1a333c8d1b1c2f8399385ff683a35ab5e274ba7b8bb7dc61c"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75130df05aae7a7ac171b3b5b24714cffeabd054ad2ebc18870b3aa4526eba23"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c34f751bf67cab69638564eee34023909380ba3e0d8ee7f6fe473079bf93f09b"}, + {file = "rpds_py-0.19.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2671cb47e50a97f419a02cd1e0c339b31de017b033186358db92f4d8e2e17d8"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c73254c256081704dba0a333457e2fb815364018788f9b501efe7c5e0ada401"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4383beb4a29935b8fa28aca8fa84c956bf545cb0c46307b091b8d312a9150e6a"}, + {file = "rpds_py-0.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dbceedcf4a9329cc665452db1aaf0845b85c666e4885b92ee0cddb1dbf7e052a"}, + {file = "rpds_py-0.19.1-cp311-none-win32.whl", hash = "sha256:f0a6d4a93d2a05daec7cb885157c97bbb0be4da739d6f9dfb02e101eb40921cd"}, + {file = "rpds_py-0.19.1-cp311-none-win_amd64.whl", hash = "sha256:c149a652aeac4902ecff2dd93c3b2681c608bd5208c793c4a99404b3e1afc87c"}, + {file = "rpds_py-0.19.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:56313be667a837ff1ea3508cebb1ef6681d418fa2913a0635386cf29cff35165"}, + {file = "rpds_py-0.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d1d7539043b2b31307f2c6c72957a97c839a88b2629a348ebabe5aa8b626d6b"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1dc59a5e7bc7f44bd0c048681f5e05356e479c50be4f2c1a7089103f1621d5"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8f78398e67a7227aefa95f876481485403eb974b29e9dc38b307bb6eb2315ea"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef07a0a1d254eeb16455d839cef6e8c2ed127f47f014bbda64a58b5482b6c836"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8124101e92c56827bebef084ff106e8ea11c743256149a95b9fd860d3a4f331f"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08ce9c95a0b093b7aec75676b356a27879901488abc27e9d029273d280438505"}, + {file = "rpds_py-0.19.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b02dd77a2de6e49078c8937aadabe933ceac04b41c5dde5eca13a69f3cf144e"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4dd02e29c8cbed21a1875330b07246b71121a1c08e29f0ee3db5b4cfe16980c4"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9c7042488165f7251dc7894cd533a875d2875af6d3b0e09eda9c4b334627ad1c"}, + {file = "rpds_py-0.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f809a17cc78bd331e137caa25262b507225854073fd319e987bd216bed911b7c"}, + {file = "rpds_py-0.19.1-cp312-none-win32.whl", hash = "sha256:3ddab996807c6b4227967fe1587febade4e48ac47bb0e2d3e7858bc621b1cace"}, + {file = "rpds_py-0.19.1-cp312-none-win_amd64.whl", hash = "sha256:32e0db3d6e4f45601b58e4ac75c6f24afbf99818c647cc2066f3e4b192dabb1f"}, + {file = "rpds_py-0.19.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:747251e428406b05fc86fee3904ee19550c4d2d19258cef274e2151f31ae9d38"}, + {file = "rpds_py-0.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dc733d35f861f8d78abfaf54035461e10423422999b360966bf1c443cbc42705"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbda75f245caecff8faa7e32ee94dfaa8312a3367397975527f29654cd17a6ed"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd04d8cab16cab5b0a9ffc7d10f0779cf1120ab16c3925404428f74a0a43205a"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2d66eb41ffca6cc3c91d8387509d27ba73ad28371ef90255c50cb51f8953301"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdf4890cda3b59170009d012fca3294c00140e7f2abe1910e6a730809d0f3f9b"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1fa67ef839bad3815124f5f57e48cd50ff392f4911a9f3cf449d66fa3df62a5"}, + {file = "rpds_py-0.19.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b82c9514c6d74b89a370c4060bdb80d2299bc6857e462e4a215b4ef7aa7b090e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c7b07959866a6afb019abb9564d8a55046feb7a84506c74a6f197cbcdf8a208e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4f580ae79d0b861dfd912494ab9d477bea535bfb4756a2269130b6607a21802e"}, + {file = "rpds_py-0.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c6d20c8896c00775e6f62d8373aba32956aa0b850d02b5ec493f486c88e12859"}, + {file = "rpds_py-0.19.1-cp313-none-win32.whl", hash = "sha256:afedc35fe4b9e30ab240b208bb9dc8938cb4afe9187589e8d8d085e1aacb8309"}, + {file = "rpds_py-0.19.1-cp313-none-win_amd64.whl", hash = "sha256:1d4af2eb520d759f48f1073ad3caef997d1bfd910dc34e41261a595d3f038a94"}, + {file = "rpds_py-0.19.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:34bca66e2e3eabc8a19e9afe0d3e77789733c702c7c43cd008e953d5d1463fde"}, + {file = "rpds_py-0.19.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:24f8ae92c7fae7c28d0fae9b52829235df83f34847aa8160a47eb229d9666c7b"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71157f9db7f6bc6599a852852f3389343bea34315b4e6f109e5cbc97c1fb2963"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d494887d40dc4dd0d5a71e9d07324e5c09c4383d93942d391727e7a40ff810b"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b3661e6d4ba63a094138032c1356d557de5b3ea6fd3cca62a195f623e381c76"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97fbb77eaeb97591efdc654b8b5f3ccc066406ccfb3175b41382f221ecc216e8"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cc4bc73e53af8e7a42c8fd7923bbe35babacfa7394ae9240b3430b5dcf16b2a"}, + {file = "rpds_py-0.19.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:35af5e4d5448fa179fd7fff0bba0fba51f876cd55212f96c8bbcecc5c684ae5c"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3511f6baf8438326e351097cecd137eb45c5f019944fe0fd0ae2fea2fd26be39"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:57863d16187995c10fe9cf911b897ed443ac68189179541734502353af33e693"}, + {file = "rpds_py-0.19.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9e318e6786b1e750a62f90c6f7fa8b542102bdcf97c7c4de2a48b50b61bd36ec"}, + {file = "rpds_py-0.19.1-cp38-none-win32.whl", hash = "sha256:53dbc35808c6faa2ce3e48571f8f74ef70802218554884787b86a30947842a14"}, + {file = "rpds_py-0.19.1-cp38-none-win_amd64.whl", hash = "sha256:8df1c283e57c9cb4d271fdc1875f4a58a143a2d1698eb0d6b7c0d7d5f49c53a1"}, + {file = "rpds_py-0.19.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e76c902d229a3aa9d5ceb813e1cbcc69bf5bda44c80d574ff1ac1fa3136dea71"}, + {file = "rpds_py-0.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de1f7cd5b6b351e1afd7568bdab94934d656abe273d66cda0ceea43bbc02a0c2"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fc5a84777cb61692d17988989690d6f34f7f95968ac81398d67c0d0994a897"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:74129d5ffc4cde992d89d345f7f7d6758320e5d44a369d74d83493429dad2de5"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e360188b72f8080fefa3adfdcf3618604cc8173651c9754f189fece068d2a45"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13e6d4840897d4e4e6b2aa1443e3a8eca92b0402182aafc5f4ca1f5e24f9270a"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f09529d2332264a902688031a83c19de8fda5eb5881e44233286b9c9ec91856d"}, + {file = "rpds_py-0.19.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0d4b52811dcbc1aba08fd88d475f75b4f6db0984ba12275d9bed1a04b2cae9b5"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd635c2c4043222d80d80ca1ac4530a633102a9f2ad12252183bcf338c1b9474"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f35b34a5184d5e0cc360b61664c1c06e866aab077b5a7c538a3e20c8fcdbf90b"}, + {file = "rpds_py-0.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d4ec0046facab83012d821b33cead742a35b54575c4edfb7ed7445f63441835f"}, + {file = "rpds_py-0.19.1-cp39-none-win32.whl", hash = "sha256:f5b8353ea1a4d7dfb59a7f45c04df66ecfd363bb5b35f33b11ea579111d4655f"}, + {file = "rpds_py-0.19.1-cp39-none-win_amd64.whl", hash = "sha256:1fb93d3486f793d54a094e2bfd9cd97031f63fcb5bc18faeb3dd4b49a1c06523"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7d5c7e32f3ee42f77d8ff1a10384b5cdcc2d37035e2e3320ded909aa192d32c3"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:89cc8921a4a5028d6dd388c399fcd2eef232e7040345af3d5b16c04b91cf3c7e"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca34e913d27401bda2a6f390d0614049f5a95b3b11cd8eff80fe4ec340a1208"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5953391af1405f968eb5701ebbb577ebc5ced8d0041406f9052638bafe52209d"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:840e18c38098221ea6201f091fc5d4de6128961d2930fbbc96806fb43f69aec1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d8b735c4d162dc7d86a9cf3d717f14b6c73637a1f9cd57fe7e61002d9cb1972"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce757c7c90d35719b38fa3d4ca55654a76a40716ee299b0865f2de21c146801c"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9421b23c85f361a133aa7c5e8ec757668f70343f4ed8fdb5a4a14abd5437244"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3b823be829407393d84ee56dc849dbe3b31b6a326f388e171555b262e8456cc1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:5e58b61dcbb483a442c6239c3836696b79f2cd8e7eec11e12155d3f6f2d886d1"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39d67896f7235b2c886fb1ee77b1491b77049dcef6fbf0f401e7b4cbed86bbd4"}, + {file = "rpds_py-0.19.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8b32cd4ab6db50c875001ba4f5a6b30c0f42151aa1fbf9c2e7e3674893fb1dc4"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c32e41de995f39b6b315d66c27dea3ef7f7c937c06caab4c6a79a5e09e2c415"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1a129c02b42d46758c87faeea21a9f574e1c858b9f358b6dd0bbd71d17713175"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:346557f5b1d8fd9966059b7a748fd79ac59f5752cd0e9498d6a40e3ac1c1875f"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31e450840f2f27699d014cfc8865cc747184286b26d945bcea6042bb6aa4d26e"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01227f8b3e6c8961490d869aa65c99653df80d2f0a7fde8c64ebddab2b9b02fd"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69084fd29bfeff14816666c93a466e85414fe6b7d236cfc108a9c11afa6f7301"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d2b88efe65544a7d5121b0c3b003ebba92bfede2ea3577ce548b69c5235185"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ea961a674172ed2235d990d7edf85d15d8dfa23ab8575e48306371c070cda67"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:5beffdbe766cfe4fb04f30644d822a1080b5359df7db3a63d30fa928375b2720"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:720f3108fb1bfa32e51db58b832898372eb5891e8472a8093008010911e324c5"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c2087dbb76a87ec2c619253e021e4fb20d1a72580feeaa6892b0b3d955175a71"}, + {file = "rpds_py-0.19.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ddd50f18ebc05ec29a0d9271e9dbe93997536da3546677f8ca00b76d477680c"}, + {file = "rpds_py-0.19.1.tar.gz", hash = "sha256:31dd5794837f00b46f4096aa8ccaa5972f73a938982e32ed817bb520c465e520"}, ] [[package]] name = "scikit-learn" -version = "1.3.1" +version = "1.5.1" description = "A set of python modules for machine learning and data mining" optional = false -python-versions = ">=3.8" -files = [ - {file = "scikit-learn-1.3.1.tar.gz", hash = "sha256:1a231cced3ee3fa04756b4a7ab532dc9417acd581a330adff5f2c01ac2831fcf"}, - {file = "scikit_learn-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3153612ff8d36fa4e35ef8b897167119213698ea78f3fd130b4068e6f8d2da5a"}, - {file = "scikit_learn-1.3.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:6bb9490fdb8e7e00f1354621689187bef3cab289c9b869688f805bf724434755"}, - {file = "scikit_learn-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7135a03af71138669f19bc96e7d0cc8081aed4b3565cc3b131135d65fc642ba"}, - {file = "scikit_learn-1.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d8dee8c1f40eeba49a85fe378bdf70a07bb64aba1a08fda1e0f48d27edfc3e6"}, - {file = "scikit_learn-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:4d379f2b34096105a96bd857b88601dffe7389bd55750f6f29aaa37bc6272eb5"}, - {file = "scikit_learn-1.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14e8775eba072ab10866a7e0596bc9906873e22c4c370a651223372eb62de180"}, - {file = "scikit_learn-1.3.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:58b0c2490eff8355dc26e884487bf8edaccf2ba48d09b194fb2f3a026dd64f9d"}, - {file = "scikit_learn-1.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f66eddfda9d45dd6cadcd706b65669ce1df84b8549875691b1f403730bdef217"}, - {file = "scikit_learn-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6448c37741145b241eeac617028ba6ec2119e1339b1385c9720dae31367f2be"}, - {file = "scikit_learn-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c413c2c850241998168bbb3bd1bb59ff03b1195a53864f0b80ab092071af6028"}, - {file = "scikit_learn-1.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ef540e09873e31569bc8b02c8a9f745ee04d8e1263255a15c9969f6f5caa627f"}, - {file = "scikit_learn-1.3.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:9147a3a4df4d401e618713880be023e36109c85d8569b3bf5377e6cd3fecdeac"}, - {file = "scikit_learn-1.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2cd3634695ad192bf71645702b3df498bd1e246fc2d529effdb45a06ab028b4"}, - {file = "scikit_learn-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c275a06c5190c5ce00af0acbb61c06374087949f643ef32d355ece12c4db043"}, - {file = "scikit_learn-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:0e1aa8f206d0de814b81b41d60c1ce31f7f2c7354597af38fae46d9c47c45122"}, - {file = "scikit_learn-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:52b77cc08bd555969ec5150788ed50276f5ef83abb72e6f469c5b91a0009bbca"}, - {file = "scikit_learn-1.3.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a683394bc3f80b7c312c27f9b14ebea7766b1f0a34faf1a2e9158d80e860ec26"}, - {file = "scikit_learn-1.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15d964d9eb181c79c190d3dbc2fff7338786bf017e9039571418a1d53dab236"}, - {file = "scikit_learn-1.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ce9233cdf0cdcf0858a5849d306490bf6de71fa7603a3835124e386e62f2311"}, - {file = "scikit_learn-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:1ec668ce003a5b3d12d020d2cde0abd64b262ac5f098b5c84cf9657deb9996a8"}, - {file = "scikit_learn-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccbbedae99325628c1d1cbe3916b7ef58a1ce949672d8d39c8b190e10219fd32"}, - {file = "scikit_learn-1.3.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:845f81c7ceb4ea6bac64ab1c9f2ce8bef0a84d0f21f3bece2126adcc213dfecd"}, - {file = "scikit_learn-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8454d57a22d856f1fbf3091bd86f9ebd4bff89088819886dc0c72f47a6c30652"}, - {file = "scikit_learn-1.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d993fb70a1d78c9798b8f2f28705bfbfcd546b661f9e2e67aa85f81052b9c53"}, - {file = "scikit_learn-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:66f7bb1fec37d65f4ef85953e1df5d3c98a0f0141d394dcdaead5a6de9170347"}, -] - -[package.dependencies] -joblib = ">=1.1.1" -numpy = ">=1.17.3,<2.0" -scipy = ">=1.5.0" -threadpoolctl = ">=2.0.0" - -[package.extras] -benchmark = ["matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=6.0.0)", "sphinx-copybutton (>=0.5.2)", "sphinx-gallery (>=0.10.1)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] -examples = ["matplotlib (>=3.1.3)", "pandas (>=1.0.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] -tests = ["black (>=23.3.0)", "matplotlib (>=3.1.3)", "mypy (>=1.3)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.0.272)", "scikit-image (>=0.16.2)"] +python-versions = ">=3.9" +files = [ + {file = "scikit_learn-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:781586c414f8cc58e71da4f3d7af311e0505a683e112f2f62919e3019abd3745"}, + {file = "scikit_learn-1.5.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5b213bc29cc30a89a3130393b0e39c847a15d769d6e59539cd86b75d276b1a7"}, + {file = "scikit_learn-1.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ff4ba34c2abff5ec59c803ed1d97d61b036f659a17f55be102679e88f926fac"}, + {file = "scikit_learn-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:161808750c267b77b4a9603cf9c93579c7a74ba8486b1336034c2f1579546d21"}, + {file = "scikit_learn-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:10e49170691514a94bb2e03787aa921b82dbc507a4ea1f20fd95557862c98dc1"}, + {file = "scikit_learn-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:154297ee43c0b83af12464adeab378dee2d0a700ccd03979e2b821e7dd7cc1c2"}, + {file = "scikit_learn-1.5.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b5e865e9bd59396220de49cb4a57b17016256637c61b4c5cc81aaf16bc123bbe"}, + {file = "scikit_learn-1.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:909144d50f367a513cee6090873ae582dba019cb3fca063b38054fa42704c3a4"}, + {file = "scikit_learn-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:689b6f74b2c880276e365fe84fe4f1befd6a774f016339c65655eaff12e10cbf"}, + {file = "scikit_learn-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:9a07f90846313a7639af6a019d849ff72baadfa4c74c778821ae0fad07b7275b"}, + {file = "scikit_learn-1.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5944ce1faada31c55fb2ba20a5346b88e36811aab504ccafb9f0339e9f780395"}, + {file = "scikit_learn-1.5.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0828673c5b520e879f2af6a9e99eee0eefea69a2188be1ca68a6121b809055c1"}, + {file = "scikit_learn-1.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:508907e5f81390e16d754e8815f7497e52139162fd69c4fdbd2dfa5d6cc88915"}, + {file = "scikit_learn-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97625f217c5c0c5d0505fa2af28ae424bd37949bb2f16ace3ff5f2f81fb4498b"}, + {file = "scikit_learn-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:da3f404e9e284d2b0a157e1b56b6566a34eb2798205cba35a211df3296ab7a74"}, + {file = "scikit_learn-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:88e0672c7ac21eb149d409c74cc29f1d611d5158175846e7a9c2427bd12b3956"}, + {file = "scikit_learn-1.5.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:7b073a27797a283187a4ef4ee149959defc350b46cbf63a84d8514fe16b69855"}, + {file = "scikit_learn-1.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b59e3e62d2be870e5c74af4e793293753565c7383ae82943b83383fdcf5cc5c1"}, + {file = "scikit_learn-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd8d3a19d4bd6dc5a7d4f358c8c3a60934dc058f363c34c0ac1e9e12a31421d"}, + {file = "scikit_learn-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:5f57428de0c900a98389c4a433d4a3cf89de979b3aa24d1c1d251802aa15e44d"}, + {file = "scikit_learn-1.5.1.tar.gz", hash = "sha256:0ea5d40c0e3951df445721927448755d3fe1d80833b0b7308ebff5d2a45e6414"}, +] + +[package.dependencies] +joblib = ">=1.2.0" +numpy = ">=1.19.5" +scipy = ">=1.6.0" +threadpoolctl = ">=3.1.0" + +[package.extras] +benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-gallery (>=0.16.0)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)"] +examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] +install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] +maintenance = ["conda-lock (==2.5.6)"] +tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.23)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.2.1)", "scikit-image (>=0.17.2)"] [[package]] name = "scipy" -version = "1.10.1" +version = "1.14.0" description = "Fundamental algorithms for scientific computing in Python" optional = false -python-versions = "<3.12,>=3.8" +python-versions = ">=3.10" files = [ - {file = "scipy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7354fd7527a4b0377ce55f286805b34e8c54b91be865bac273f527e1b839019"}, - {file = "scipy-1.10.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4b3f429188c66603a1a5c549fb414e4d3bdc2a24792e061ffbd607d3d75fd84e"}, - {file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1553b5dcddd64ba9a0d95355e63fe6c3fc303a8fd77c7bc91e77d61363f7433f"}, - {file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c0ff64b06b10e35215abce517252b375e580a6125fd5fdf6421b98efbefb2d2"}, - {file = "scipy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:fae8a7b898c42dffe3f7361c40d5952b6bf32d10c4569098d276b4c547905ee1"}, - {file = "scipy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f1564ea217e82c1bbe75ddf7285ba0709ecd503f048cb1236ae9995f64217bd"}, - {file = "scipy-1.10.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d925fa1c81b772882aa55bcc10bf88324dadb66ff85d548c71515f6689c6dac5"}, - {file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaea0a6be54462ec027de54fca511540980d1e9eea68b2d5c1dbfe084797be35"}, - {file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15a35c4242ec5f292c3dd364a7c71a61be87a3d4ddcc693372813c0b73c9af1d"}, - {file = "scipy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:43b8e0bcb877faf0abfb613d51026cd5cc78918e9530e375727bf0625c82788f"}, - {file = "scipy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5678f88c68ea866ed9ebe3a989091088553ba12c6090244fdae3e467b1139c35"}, - {file = "scipy-1.10.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:39becb03541f9e58243f4197584286e339029e8908c46f7221abeea4b749fa88"}, - {file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bce5869c8d68cf383ce240e44c1d9ae7c06078a9396df68ce88a1230f93a30c1"}, - {file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07c3457ce0b3ad5124f98a86533106b643dd811dd61b548e78cf4c8786652f6f"}, - {file = "scipy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:049a8bbf0ad95277ffba9b3b7d23e5369cc39e66406d60422c8cfef40ccc8415"}, - {file = "scipy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cd9f1027ff30d90618914a64ca9b1a77a431159df0e2a195d8a9e8a04c78abf9"}, - {file = "scipy-1.10.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:79c8e5a6c6ffaf3a2262ef1be1e108a035cf4f05c14df56057b64acc5bebffb6"}, - {file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51af417a000d2dbe1ec6c372dfe688e041a7084da4fdd350aeb139bd3fb55353"}, - {file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601"}, - {file = "scipy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ff7f37b1bf4417baca958d254e8e2875d0cc23aaadbe65b3d5b3077b0eb23ea"}, - {file = "scipy-1.10.1.tar.gz", hash = "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1"}, + {file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0"}, + {file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0"}, + {file = "scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d"}, + {file = "scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94c164a9e2498e68308e6e148646e486d979f7fcdb8b4cf34b5441894bdb9caf"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a7d46c3e0aea5c064e734c3eac5cf9eb1f8c4ceee756262f2c7327c4c2691c86"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eee2989868e274aae26125345584254d97c56194c072ed96cb433f32f692ed8"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3154691b9f7ed73778d746da2df67a19d046a6c8087c8b385bc4cdb2cfca74"}, + {file = "scipy-1.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c40003d880f39c11c1edbae8144e3813904b10514cd3d3d00c277ae996488cdb"}, + {file = "scipy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b083c8940028bb7e0b4172acafda6df762da1927b9091f9611b0bcd8676f2bc"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff2438ea1330e06e53c424893ec0072640dac00f29c6a43a575cbae4c99b2b9"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bbc0471b5f22c11c389075d091d3885693fd3f5e9a54ce051b46308bc787e5d4"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:64b2ff514a98cf2bb734a9f90d32dc89dc6ad4a4a36a312cd0d6327170339eb0"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:7d3da42fbbbb860211a811782504f38ae7aaec9de8764a9bef6b262de7a2b50f"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d91db2c41dd6c20646af280355d41dfa1ec7eead235642178bd57635a3f82209"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a01cc03bcdc777c9da3cfdcc74b5a75caffb48a6c39c8450a9a05f82c4250a14"}, + {file = "scipy-1.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65df4da3c12a2bb9ad52b86b4dcf46813e869afb006e58be0f516bc370165159"}, + {file = "scipy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:4c4161597c75043f7154238ef419c29a64ac4a7c889d588ea77690ac4d0d9b20"}, + {file = "scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b"}, ] [package.dependencies] -numpy = ">=1.19.5,<1.27.0" +numpy = ">=1.23.5,<2.3" [package.extras] -dev = ["click", "doit (>=0.36.0)", "flake8", "mypy", "pycodestyle", "pydevtool", "rich-click", "typing_extensions"] -doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] -test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "secretstorage" @@ -3152,13 +3164,13 @@ jeepney = ">=0.6" [[package]] name = "shellingham" -version = "1.5.0.post1" +version = "1.5.4" description = "Tool to Detect Surrounding Shell" optional = false python-versions = ">=3.7" files = [ - {file = "shellingham-1.5.0.post1-py2.py3-none-any.whl", hash = "sha256:368bf8c00754fd4f55afb7bbb86e272df77e4dc76ac29dbcbb81a59e9fc15744"}, - {file = "shellingham-1.5.0.post1.tar.gz", hash = "sha256:823bc5fb5c34d60f285b624e7264f4dda254bc803a3774a147bf99c0e3004a28"}, + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, ] [[package]] @@ -3174,13 +3186,13 @@ files = [ [[package]] name = "smmap" -version = "5.0.0" +version = "5.0.1" description = "A pure Python implementation of a sliding window memory map manager" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, - {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, ] [[package]] @@ -3196,13 +3208,13 @@ files = [ [[package]] name = "soupsieve" -version = "2.4.1" +version = "2.5" description = "A modern CSS selector implementation for Beautiful Soup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, - {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, ] [[package]] @@ -3222,7 +3234,6 @@ babel = ">=1.3" colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} docutils = ">=0.14,<0.18" imagesize = "*" -importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} Jinja2 = ">=2.3" packaging = "*" Pygments = ">=2.0" @@ -3242,18 +3253,18 @@ test = ["cython", "html5lib", "pytest", "pytest-cov", "typed-ast"] [[package]] name = "sphinx-rtd-theme" -version = "1.2.2" +version = "1.3.0" description = "Read the Docs theme for Sphinx" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "sphinx_rtd_theme-1.2.2-py2.py3-none-any.whl", hash = "sha256:6a7e7d8af34eb8fc57d52a09c6b6b9c46ff44aea5951bc831eeb9245378f3689"}, - {file = "sphinx_rtd_theme-1.2.2.tar.gz", hash = "sha256:01c5c5a72e2d025bd23d1f06c59a4831b06e6ce6c01fdd5ebfe9986c0a880fc7"}, + {file = "sphinx_rtd_theme-1.3.0-py2.py3-none-any.whl", hash = "sha256:46ddef89cc2416a81ecfbeaceab1881948c014b1b6e4450b815311a89fb977b0"}, + {file = "sphinx_rtd_theme-1.3.0.tar.gz", hash = "sha256:590b030c7abb9cf038ec053b95e5380b5c70d61591eb0b552063fbe7c41f0931"}, ] [package.dependencies] docutils = "<0.19" -sphinx = ">=1.6,<7" +sphinx = ">=1.6,<8" sphinxcontrib-jquery = ">=4,<5" [package.extras] @@ -3261,68 +3272,70 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] [[package]] name = "sphinx-tabs" -version = "3.4.0" +version = "3.4.5" description = "Tabbed views for Sphinx" optional = false python-versions = "~=3.7" files = [ - {file = "sphinx-tabs-3.4.0.tar.gz", hash = "sha256:75e97ce10b74700deaf87b662539a293c8afc9dfa9d21f126b860118064cb0c5"}, - {file = "sphinx_tabs-3.4.0-py3-none-any.whl", hash = "sha256:31dbe7594b5ef4cfa76a7960448d4607dca167ff21467000213920572c302072"}, + {file = "sphinx-tabs-3.4.5.tar.gz", hash = "sha256:ba9d0c1e3e37aaadd4b5678449eb08176770e0fc227e769b6ce747df3ceea531"}, + {file = "sphinx_tabs-3.4.5-py3-none-any.whl", hash = "sha256:92cc9473e2ecf1828ca3f6617d0efc0aa8acb06b08c56ba29d1413f2f0f6cf09"}, ] [package.dependencies] -docutils = ">=0.17.0,<0.18.0" -jinja2 = "<3.1.0" +docutils = "*" pygments = "*" -sphinx = ">=2,<6" +sphinx = "*" [package.extras] code-style = ["pre-commit (==2.13.0)"] -testing = ["bs4", "coverage", "pygments", "pytest (>=7.1,<8)", "pytest-cov", "pytest-regressions", "rinohtype", "sphinx-testing"] +testing = ["bs4", "coverage", "pygments", "pytest (>=7.1,<8)", "pytest-cov", "pytest-regressions", "rinohtype"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.4" +version = "1.0.8" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, - {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, + {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, + {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, ] [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.2" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +version = "1.0.6" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, - {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, + {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, + {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, ] [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.1" +version = "2.0.6" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, - {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, + {file = "sphinxcontrib_htmlhelp-2.0.6-py3-none-any.whl", hash = "sha256:1b9af5a2671a61410a868fce050cab7ca393c218e6205cbc7f590136f207395c"}, + {file = "sphinxcontrib_htmlhelp-2.0.6.tar.gz", hash = "sha256:c6597da06185f0e3b4dc952777a04200611ef563882e0c244d27a15ee22afa73"}, ] [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -3355,43 +3368,45 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.3" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +version = "1.0.8" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, - {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, + {file = "sphinxcontrib_qthelp-1.0.8-py3-none-any.whl", hash = "sha256:323d6acc4189af76dfe94edd2a27d458902319b60fcca2aeef3b2180c106a75f"}, + {file = "sphinxcontrib_qthelp-1.0.8.tar.gz", hash = "sha256:db3f8fa10789c7a8e76d173c23364bdf0ebcd9449969a9e6a3dd31b8b7469f03"}, ] [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] +standalone = ["Sphinx (>=5)"] +test = ["defusedxml (>=0.7.1)", "pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.5" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +version = "1.1.10" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, - {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, + {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, + {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, ] [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "stack-data" -version = "0.6.2" +version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" optional = false python-versions = "*" files = [ - {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"}, - {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"}, + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, ] [package.dependencies] @@ -3404,13 +3419,13 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "stevedore" -version = "5.1.0" +version = "5.2.0" description = "Manage dynamic plugins for Python applications" optional = false python-versions = ">=3.8" files = [ - {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, - {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, + {file = "stevedore-5.2.0-py3-none-any.whl", hash = "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9"}, + {file = "stevedore-5.2.0.tar.gz", hash = "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d"}, ] [package.dependencies] @@ -3418,24 +3433,24 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" [[package]] name = "threadpoolctl" -version = "3.2.0" +version = "3.5.0" description = "threadpoolctl" optional = false python-versions = ">=3.8" files = [ - {file = "threadpoolctl-3.2.0-py3-none-any.whl", hash = "sha256:2b7818516e423bdaebb97c723f86a7c6b0a83d3f3b0970328d66f4d9104dc032"}, - {file = "threadpoolctl-3.2.0.tar.gz", hash = "sha256:c96a0ba3bdddeaca37dc4cc7344aafad41cdb8c313f74fdfe387a867bba93355"}, + {file = "threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467"}, + {file = "threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107"}, ] [[package]] name = "tinycss2" -version = "1.2.1" +version = "1.3.0" description = "A tiny CSS parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, - {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, + {file = "tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"}, + {file = "tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d"}, ] [package.dependencies] @@ -3443,7 +3458,7 @@ webencodings = ">=0.4" [package.extras] doc = ["sphinx", "sphinx_rtd_theme"] -test = ["flake8", "isort", "pytest"] +test = ["pytest", "ruff"] [[package]] name = "toml" @@ -3469,33 +3484,33 @@ files = [ [[package]] name = "tomlkit" -version = "0.11.8" +version = "0.13.0" description = "Style preserving TOML library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, - {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, + {file = "tomlkit-0.13.0-py3-none-any.whl", hash = "sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264"}, + {file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"}, ] [[package]] name = "tornado" -version = "6.3.3" +version = "6.4.1" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "tornado-6.3.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:502fba735c84450974fec147340016ad928d29f1e91f49be168c0a4c18181e1d"}, - {file = "tornado-6.3.3-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:805d507b1f588320c26f7f097108eb4023bbaa984d63176d1652e184ba24270a"}, - {file = "tornado-6.3.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bd19ca6c16882e4d37368e0152f99c099bad93e0950ce55e71daed74045908f"}, - {file = "tornado-6.3.3-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ac51f42808cca9b3613f51ffe2a965c8525cb1b00b7b2d56828b8045354f76a"}, - {file = "tornado-6.3.3-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71a8db65160a3c55d61839b7302a9a400074c9c753040455494e2af74e2501f2"}, - {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ceb917a50cd35882b57600709dd5421a418c29ddc852da8bcdab1f0db33406b0"}, - {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:7d01abc57ea0dbb51ddfed477dfe22719d376119844e33c661d873bf9c0e4a16"}, - {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9dc4444c0defcd3929d5c1eb5706cbe1b116e762ff3e0deca8b715d14bf6ec17"}, - {file = "tornado-6.3.3-cp38-abi3-win32.whl", hash = "sha256:65ceca9500383fbdf33a98c0087cb975b2ef3bfb874cb35b8de8740cf7f41bd3"}, - {file = "tornado-6.3.3-cp38-abi3-win_amd64.whl", hash = "sha256:22d3c2fa10b5793da13c807e6fc38ff49a4f6e1e3868b0a6f4164768bb8e20f5"}, - {file = "tornado-6.3.3.tar.gz", hash = "sha256:e7d8db41c0181c80d76c982aacc442c0783a2c54d6400fe028954201a2e032fe"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, + {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, + {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, + {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, ] [[package]] @@ -3514,39 +3529,39 @@ linecache2 = "*" [[package]] name = "traitlets" -version = "5.9.0" +version = "5.14.3" description = "Traitlets Python configuration system" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"}, - {file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"}, + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "trove-classifiers" -version = "2023.7.6" +version = "2024.7.2" description = "Canonical source for classifiers on PyPI (pypi.org)." optional = false python-versions = "*" files = [ - {file = "trove-classifiers-2023.7.6.tar.gz", hash = "sha256:8a8e168b51d20fed607043831d37632bb50919d1c80a64e0f1393744691a8b22"}, - {file = "trove_classifiers-2023.7.6-py3-none-any.whl", hash = "sha256:b420d5aa048ee7c456233a49203f7d58d1736af4a6cde637657d78c13ab7969b"}, + {file = "trove_classifiers-2024.7.2-py3-none-any.whl", hash = "sha256:ccc57a33717644df4daca018e7ec3ef57a835c48e96a1e71fc07eb7edac67af6"}, + {file = "trove_classifiers-2024.7.2.tar.gz", hash = "sha256:8328f2ac2ce3fd773cbb37c765a0ed7a83f89dc564c7d452f039b69249d0ac35"}, ] [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -3567,49 +3582,50 @@ traceback2 = "*" [[package]] name = "urllib3" -version = "1.26.18" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.8" files = [ - {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, - {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.2" +version = "20.26.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.2-py3-none-any.whl", hash = "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff"}, - {file = "virtualenv-20.24.2.tar.gz", hash = "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0"}, + {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, + {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "wcwidth" -version = "0.2.6" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, - {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [[package]] @@ -3625,104 +3641,93 @@ files = [ [[package]] name = "xattr" -version = "0.10.1" +version = "1.1.0" description = "Python wrapper for extended filesystem attributes" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "xattr-0.10.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:16a660a883e703b311d1bbbcafc74fa877585ec081cd96e8dd9302c028408ab1"}, - {file = "xattr-0.10.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1e2973e72faa87ca29d61c23b58c3c89fe102d1b68e091848b0e21a104123503"}, - {file = "xattr-0.10.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:13279fe8f7982e3cdb0e088d5cb340ce9cbe5ef92504b1fd80a0d3591d662f68"}, - {file = "xattr-0.10.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1dc9b9f580ef4b8ac5e2c04c16b4d5086a611889ac14ecb2e7e87170623a0b75"}, - {file = "xattr-0.10.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:485539262c2b1f5acd6b6ea56e0da2bc281a51f74335c351ea609c23d82c9a79"}, - {file = "xattr-0.10.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:295b3ab335fcd06ca0a9114439b34120968732e3f5e9d16f456d5ec4fa47a0a2"}, - {file = "xattr-0.10.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:a126eb38e14a2f273d584a692fe36cff760395bf7fc061ef059224efdb4eb62c"}, - {file = "xattr-0.10.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:b0e919c24f5b74428afa91507b15e7d2ef63aba98e704ad13d33bed1288dca81"}, - {file = "xattr-0.10.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:e31d062cfe1aaeab6ba3db6bd255f012d105271018e647645941d6609376af18"}, - {file = "xattr-0.10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:209fb84c09b41c2e4cf16dd2f481bb4a6e2e81f659a47a60091b9bcb2e388840"}, - {file = "xattr-0.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c4120090dac33eddffc27e487f9c8f16b29ff3f3f8bcb2251b2c6c3f974ca1e1"}, - {file = "xattr-0.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e739d624491267ec5bb740f4eada93491de429d38d2fcdfb97b25efe1288eca"}, - {file = "xattr-0.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2677d40b95636f3482bdaf64ed9138fb4d8376fb7933f434614744780e46e42d"}, - {file = "xattr-0.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40039f1532c4456fd0f4c54e9d4e01eb8201248c321c6c6856262d87e9a99593"}, - {file = "xattr-0.10.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:148466e5bb168aba98f80850cf976e931469a3c6eb11e9880d9f6f8b1e66bd06"}, - {file = "xattr-0.10.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0aedf55b116beb6427e6f7958ccd80a8cbc80e82f87a4cd975ccb61a8d27b2ee"}, - {file = "xattr-0.10.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c3024a9ff157247c8190dd0eb54db4a64277f21361b2f756319d9d3cf20e475f"}, - {file = "xattr-0.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f1be6e733e9698f645dbb98565bb8df9b75e80e15a21eb52787d7d96800e823b"}, - {file = "xattr-0.10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7880c8a54c18bc091a4ce0adc5c6d81da1c748aec2fe7ac586d204d6ec7eca5b"}, - {file = "xattr-0.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:89c93b42c3ba8aedbc29da759f152731196c2492a2154371c0aae3ef8ba8301b"}, - {file = "xattr-0.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6b905e808df61b677eb972f915f8a751960284358b520d0601c8cbc476ba2df6"}, - {file = "xattr-0.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ef954d0655f93a34d07d0cc7e02765ec779ff0b59dc898ee08c6326ad614d5"}, - {file = "xattr-0.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:199b20301b6acc9022661412346714ce764d322068ef387c4de38062474db76c"}, - {file = "xattr-0.10.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec0956a8ab0f0d3f9011ba480f1e1271b703d11542375ef73eb8695a6bd4b78b"}, - {file = "xattr-0.10.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffcb57ca1be338d69edad93cf59aac7c6bb4dbb92fd7bf8d456c69ea42f7e6d2"}, - {file = "xattr-0.10.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f0563196ee54756fe2047627d316977dc77d11acd7a07970336e1a711e934db"}, - {file = "xattr-0.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc354f086f926a1c7f04886f97880fed1a26d20e3bc338d0d965fd161dbdb8ab"}, - {file = "xattr-0.10.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c0cd2d02ef2fb45ecf2b0da066a58472d54682c6d4f0452dfe7ae2f3a76a42ea"}, - {file = "xattr-0.10.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49626096ddd72dcc1654aadd84b103577d8424f26524a48d199847b5d55612d0"}, - {file = "xattr-0.10.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ceaa26bef8fcb17eb59d92a7481c2d15d20211e217772fb43c08c859b01afc6a"}, - {file = "xattr-0.10.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c014c371391f28f8cd27d73ea59f42b30772cd640b5a2538ad4f440fd9190b"}, - {file = "xattr-0.10.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:46c32cd605673606b9388a313b0050ee7877a0640d7561eea243ace4fa2cc5a6"}, - {file = "xattr-0.10.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:772b22c4ff791fe5816a7c2a1c9fcba83f9ab9bea138eb44d4d70f34676232b4"}, - {file = "xattr-0.10.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:183ad611a2d70b5a3f5f7aadef0fcef604ea33dcf508228765fd4ddac2c7321d"}, - {file = "xattr-0.10.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8068df3ebdfa9411e58d5ae4a05d807ec5994645bb01af66ec9f6da718b65c5b"}, - {file = "xattr-0.10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bc40570155beb85e963ae45300a530223d9822edfdf09991b880e69625ba38a"}, - {file = "xattr-0.10.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:436e1aaf23c07e15bed63115f1712d2097e207214fc6bcde147c1efede37e2c5"}, - {file = "xattr-0.10.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7298455ccf3a922d403339781b10299b858bb5ec76435445f2da46fb768e31a5"}, - {file = "xattr-0.10.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:986c2305c6c1a08f78611eb38ef9f1f47682774ce954efb5a4f3715e8da00d5f"}, - {file = "xattr-0.10.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5dc6099e76e33fa3082a905fe59df766b196534c705cf7a2e3ad9bed2b8a180e"}, - {file = "xattr-0.10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:042ad818cda6013162c0bfd3816f6b74b7700e73c908cde6768da824686885f8"}, - {file = "xattr-0.10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9d4c306828a45b41b76ca17adc26ac3dc00a80e01a5ba85d71df2a3e948828f2"}, - {file = "xattr-0.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a606280b0c9071ef52572434ecd3648407b20df3d27af02c6592e84486b05894"}, - {file = "xattr-0.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5b49d591cf34cda2079fd7a5cb2a7a1519f54dc2e62abe3e0720036f6ed41a85"}, - {file = "xattr-0.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8705ac6791426559c1a5c2b88bb2f0e83dc5616a09b4500899bfff6a929302"}, - {file = "xattr-0.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5ea974930e876bc5c146f54ac0f85bb39b7b5de2b6fc63f90364712ae368ebe"}, - {file = "xattr-0.10.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f55a2dd73a12a1ae5113c5d9cd4b4ab6bf7950f4d76d0a1a0c0c4264d50da61d"}, - {file = "xattr-0.10.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:475c38da0d3614cc5564467c4efece1e38bd0705a4dbecf8deeb0564a86fb010"}, - {file = "xattr-0.10.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:925284a4a28e369459b2b7481ea22840eed3e0573a4a4c06b6b0614ecd27d0a7"}, - {file = "xattr-0.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa32f1b45fed9122bed911de0fcc654da349e1f04fa4a9c8ef9b53e1cc98b91e"}, - {file = "xattr-0.10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c5d3d0e728bace64b74c475eb4da6148cd172b2d23021a1dcd055d92f17619ac"}, - {file = "xattr-0.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8faaacf311e2b5cc67c030c999167a78a9906073e6abf08eaa8cf05b0416515c"}, - {file = "xattr-0.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cc6b8d5ca452674e1a96e246a3d2db5f477aecbc7c945c73f890f56323e75203"}, - {file = "xattr-0.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3725746a6502f40f72ef27e0c7bfc31052a239503ff3eefa807d6b02a249be22"}, - {file = "xattr-0.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:789bd406d1aad6735e97b20c6d6a1701e1c0661136be9be862e6a04564da771f"}, - {file = "xattr-0.10.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9a7a807ab538210ff8532220d8fc5e2d51c212681f63dbd4e7ede32543b070f"}, - {file = "xattr-0.10.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3e5825b5fc99ecdd493b0cc09ec35391e7a451394fdf623a88b24726011c950d"}, - {file = "xattr-0.10.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80638d1ce7189dc52f26c234cee3522f060fadab6a8bc3562fe0ddcbe11ba5a4"}, - {file = "xattr-0.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3ff0dbe4a6ce2ce065c6de08f415bcb270ecfd7bf1655a633ddeac695ce8b250"}, - {file = "xattr-0.10.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5267e5f9435c840d2674194150b511bef929fa7d3bc942a4a75b9eddef18d8d8"}, - {file = "xattr-0.10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b27dfc13b193cb290d5d9e62f806bb9a99b00cd73bb6370d556116ad7bb5dc12"}, - {file = "xattr-0.10.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:636ebdde0277bce4d12d2ef2550885804834418fee0eb456b69be928e604ecc4"}, - {file = "xattr-0.10.1-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d60c27922ec80310b45574351f71e0dd3a139c5295e8f8b19d19c0010196544f"}, - {file = "xattr-0.10.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b34df5aad035d0343bd740a95ca30db99b776e2630dca9cc1ba8e682c9cc25ea"}, - {file = "xattr-0.10.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f24a7c04ff666d0fe905dfee0a84bc899d624aeb6dccd1ea86b5c347f15c20c1"}, - {file = "xattr-0.10.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3878e1aff8eca64badad8f6d896cb98c52984b1e9cd9668a3ab70294d1ef92d"}, - {file = "xattr-0.10.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4abef557028c551d59cf2fb3bf63f2a0c89f00d77e54c1c15282ecdd56943496"}, - {file = "xattr-0.10.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0e14bd5965d3db173d6983abdc1241c22219385c22df8b0eb8f1846c15ce1fee"}, - {file = "xattr-0.10.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f9be588a4b6043b03777d50654c6079af3da60cc37527dbb80d36ec98842b1e"}, - {file = "xattr-0.10.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bc4ae264aa679aacf964abf3ea88e147eb4a22aea6af8c6d03ebdebd64cfd6"}, - {file = "xattr-0.10.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:827b5a97673b9997067fde383a7f7dc67342403093b94ea3c24ae0f4f1fec649"}, - {file = "xattr-0.10.1.tar.gz", hash = "sha256:c12e7d81ffaa0605b3ac8c22c2994a8e18a9cf1c59287a1b7722a2289c952ec5"}, -] - -[package.dependencies] -cffi = ">=1.0" + {file = "xattr-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef2fa0f85458736178fd3dcfeb09c3cf423f0843313e25391db2cfd1acec8888"}, + {file = "xattr-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ccab735d0632fe71f7d72e72adf886f45c18b7787430467ce0070207882cfe25"}, + {file = "xattr-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9013f290387f1ac90bccbb1926555ca9aef75651271098d99217284d9e010f7c"}, + {file = "xattr-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcd5dfbcee73c7be057676ecb900cabb46c691aff4397bf48c579ffb30bb963"}, + {file = "xattr-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6480589c1dac7785d1f851347a32c4a97305937bf7b488b857fe8b28a25de9e9"}, + {file = "xattr-1.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08f61cbed52dc6f7c181455826a9ff1e375ad86f67dd9d5eb7663574abb32451"}, + {file = "xattr-1.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:918e1f83f2e8a072da2671eac710871ee5af337e9bf8554b5ce7f20cdb113186"}, + {file = "xattr-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0f06e0c1e4d06b4e0e49aaa1184b6f0e81c3758c2e8365597918054890763b53"}, + {file = "xattr-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a641ac038a9f53d2f696716147ca4dbd6a01998dc9cd4bc628801bc0df7f4d"}, + {file = "xattr-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7e4ca0956fd11679bb2e0c0d6b9cdc0f25470cc00d8da173bb7656cc9a9cf104"}, + {file = "xattr-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6881b120f9a4b36ccd8a28d933bc0f6e1de67218b6ce6e66874e0280fc006844"}, + {file = "xattr-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dab29d9288aa28e68a6f355ddfc3f0a7342b40c9012798829f3e7bd765e85c2c"}, + {file = "xattr-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0c80bbf55339c93770fc294b4b6586b5bf8e85ec00a4c2d585c33dbd84b5006"}, + {file = "xattr-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1418705f253b6b6a7224b69773842cac83fcbcd12870354b6e11dd1cd54630f"}, + {file = "xattr-1.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:687e7d18611ef8d84a6ecd8f4d1ab6757500c1302f4c2046ce0aa3585e13da3f"}, + {file = "xattr-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6ceb9efe0657a982ccb8b8a2efe96b690891779584c901d2f920784e5d20ae3"}, + {file = "xattr-1.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b489b7916f239100956ea0b39c504f3c3a00258ba65677e4c8ba1bd0b5513446"}, + {file = "xattr-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0a9c431b0e66516a078125e9a273251d4b8e5ba84fe644b619f2725050d688a0"}, + {file = "xattr-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1a5921ea3313cc1c57f2f53b63ea8ca9a91e48f4cc7ebec057d2447ec82c7efe"}, + {file = "xattr-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f6ad2a7bd5e6cf71d4a862413234a067cf158ca0ae94a40d4b87b98b62808498"}, + {file = "xattr-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0683dae7609f7280b0c89774d00b5957e6ffcb181c6019c46632b389706b77e6"}, + {file = "xattr-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54cb15cd94e5ef8a0ef02309f1bf973ba0e13c11e87686e983f371948cfee6af"}, + {file = "xattr-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff6223a854229055e803c2ad0c0ea9a6da50c6be30d92c198cf5f9f28819a921"}, + {file = "xattr-1.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d44e8f955218638c9ab222eed21e9bd9ab430d296caf2176fb37abe69a714e5c"}, + {file = "xattr-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:caab2c2986c30f92301f12e9c50415d324412e8e6a739a52a603c3e6a54b3610"}, + {file = "xattr-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d6eb7d5f281014cd44e2d847a9107491af1bf3087f5afeded75ed3e37ec87239"}, + {file = "xattr-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:47a3bdfe034b4fdb70e5941d97037405e3904accc28e10dbef6d1c9061fb6fd7"}, + {file = "xattr-1.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:00d2b415cf9d6a24112d019e721aa2a85652f7bbc9f3b9574b2d1cd8668eb491"}, + {file = "xattr-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:78b377832dd0ee408f9f121a354082c6346960f7b6b1480483ed0618b1912120"}, + {file = "xattr-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6461a43b585e5f2e049b39bcbfcb6391bfef3c5118231f1b15d10bdb89ef17fe"}, + {file = "xattr-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24d97f0d28f63695e3344ffdabca9fcc30c33e5c8ccc198c7524361a98d526f2"}, + {file = "xattr-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ad47d89968c9097900607457a0c89160b4771601d813e769f68263755516065"}, + {file = "xattr-1.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc53cab265f6e8449bd683d5ee3bc5a191e6dd940736f3de1a188e6da66b0653"}, + {file = "xattr-1.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cd11e917f5b89f2a0ad639d9875943806c6c9309a3dd02da5a3e8ef92db7bed9"}, + {file = "xattr-1.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9c5a78c7558989492c4cb7242e490ffb03482437bf782967dfff114e44242343"}, + {file = "xattr-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cebcf8a303a44fbc439b68321408af7267507c0d8643229dbb107f6c132d389c"}, + {file = "xattr-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b0d73150f2f9655b4da01c2369eb33a294b7f9d56eccb089819eafdbeb99f896"}, + {file = "xattr-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:793c01deaadac50926c0e1481702133260c7cb5e62116762f6fe1543d07b826f"}, + {file = "xattr-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e189e440bcd04ccaad0474720abee6ee64890823ec0db361fb0a4fb5e843a1bf"}, + {file = "xattr-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afacebbc1fa519f41728f8746a92da891c7755e6745164bd0d5739face318e86"}, + {file = "xattr-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b1664edf003153ac8d1911e83a0fc60db1b1b374ee8ac943f215f93754a1102"}, + {file = "xattr-1.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda2684228798e937a7c29b0e1c7ef3d70e2b85390a69b42a1c61b2039ba81de"}, + {file = "xattr-1.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b735ac2625a4fc2c9343b19f806793db6494336338537d2911c8ee4c390dda46"}, + {file = "xattr-1.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fa6a7af7a4ada43f15ccc58b6f9adcdbff4c36ba040013d2681e589e07ae280a"}, + {file = "xattr-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1059b2f726e2702c8bbf9bbf369acfc042202a4cc576c2dec6791234ad5e948"}, + {file = "xattr-1.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e2255f36ebf2cb2dbf772a7437ad870836b7396e60517211834cf66ce678b595"}, + {file = "xattr-1.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba4f80b9855cc98513ddf22b7ad8551bc448c70d3147799ea4f6c0b758fb466"}, + {file = "xattr-1.1.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cb70c16e7c3ae6ba0ab6c6835c8448c61d8caf43ea63b813af1f4dbe83dd156"}, + {file = "xattr-1.1.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83652910ef6a368b77b00825ad67815e5c92bfab551a848ca66e9981d14a7519"}, + {file = "xattr-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7a92aff66c43fa3e44cbeab7cbeee66266c91178a0f595e044bf3ce51485743b"}, + {file = "xattr-1.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d4f71b673339aeaae1f6ea9ef8ea6c9643c8cd0df5003b9a0eaa75403e2e06c"}, + {file = "xattr-1.1.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a20de1c47b5cd7b47da61799a3b34e11e5815d716299351f82a88627a43f9a96"}, + {file = "xattr-1.1.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23705c7079b05761ff2fa778ad17396e7599c8759401abc05b312dfb3bc99f69"}, + {file = "xattr-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:27272afeba8422f2a9d27e1080a9a7b807394e88cce73db9ed8d2dde3afcfb87"}, + {file = "xattr-1.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd43978966de3baf4aea367c99ffa102b289d6c2ea5f3d9ce34a203dc2f2ab73"}, + {file = "xattr-1.1.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ded771eaf27bb4eb3c64c0d09866460ee8801d81dc21097269cf495b3cac8657"}, + {file = "xattr-1.1.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca300c0acca4f0cddd2332bb860ef58e1465d376364f0e72a1823fdd58e90d"}, + {file = "xattr-1.1.0.tar.gz", hash = "sha256:fecbf3b05043ed3487a28190dec3e4c4d879b2fcec0e30bafd8ec5d4b6043630"}, +] + +[package.dependencies] +cffi = ">=1.16.0" + +[package.extras] +test = ["pytest"] [[package]] name = "zipp" -version = "3.16.2" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, - {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" -python-versions = ">=3.8, <3.11" -content-hash = "d2ed74644f3e06a1e22de2a3ae7469cb8935a019442c43ed98dffdc3b6f13e0e" +python-versions = ">=3.10, <3.11" +content-hash = "699b81595c61a64c61d4b845d250e948d8230a063d676e81570b3556a47a3f44" diff --git a/pyproject.toml b/pyproject.toml index 9d5f7f851..6751f518e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ packages = [ {include = "tests"} ] include = ["tutorials"] -version = "0.8.0.dev0" +version = "0.9.0.dev0" readme = "README.md" description = "A Software Framework for Neuromorphic Computing" homepage = "https://lava-nc.org/" @@ -46,13 +46,13 @@ classifiers = [ "Discussions" = "https://github.com/lava-nc/lava/discussions" [tool.poetry.dependencies] -python = ">=3.8, <3.11" +python = ">=3.10, <3.11" numpy = "^1.24.4" scipy = "^1.10.1" networkx = "<=2.8.7" asteval = "^0.9.31" -scikit-learn = "^1.3.1" +scikit-learn = "^1.5.0" [tool.poetry.dev-dependencies] bandit = "1.7.4" diff --git a/src/lava/frameworks/loihi2.py b/src/lava/frameworks/loihi2.py new file mode 100644 index 000000000..07007d767 --- /dev/null +++ b/src/lava/frameworks/loihi2.py @@ -0,0 +1,14 @@ +# Copyright (C) 2022-23 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +from lava.networks.gradedvecnetwork import (InputVec, OutputVec, GradedVec, + GradedDense, GradedSparse, + ProductVec, + LIFVec, + NormalizeNet) + +from lava.networks.resfire import ResFireVec + +from lava.magma.core.run_conditions import RunSteps, RunContinuous +from lava.magma.core.run_configs import Loihi2SimCfg, Loihi2HwCfg diff --git a/src/lava/magma/compiler/channel_map.py b/src/lava/magma/compiler/channel_map.py index 2eadd52cc..5c963792c 100644 --- a/src/lava/magma/compiler/channel_map.py +++ b/src/lava/magma/compiler/channel_map.py @@ -11,6 +11,7 @@ from lava.magma.compiler.utils import PortInitializer from lava.magma.core.process.ports.ports import AbstractPort from lava.magma.core.process.ports.ports import AbstractSrcPort, AbstractDstPort +from lava.magma.core.process.process import AbstractProcess @dataclass(eq=True, frozen=True) @@ -27,6 +28,10 @@ class Payload: dst_port_initializer: PortInitializer = None +def lmt_init_id(): + return -1 + + class ChannelMap(dict): """The ChannelMap is used by the SubCompilers during compilation to communicate how they are planning to partition Processes onto their @@ -35,7 +40,7 @@ class ChannelMap(dict): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._initializers_lookup = dict() - self._lmt_allocation_dict: ty.Dict[int, int] = defaultdict(lambda: -1) + self._lmt_allocation_dict: ty.Dict[int, int] = defaultdict(lmt_init_id) def __setitem__( self, key: PortPair, value: Payload, dict_setitem=dict.__setitem__ @@ -91,7 +96,8 @@ def from_proc_groups(self, return channel_map @classmethod - def _get_port_pairs_from_proc_groups(self, proc_groups: ty.List[ProcGroup]): + def _get_port_pairs_from_proc_groups(cls, + proc_groups: ty.List[ProcGroup]): """Loop over processes connectivity and get all connected port pairs.""" processes = list(itertools.chain.from_iterable(proc_groups)) port_pairs = [] @@ -102,7 +108,7 @@ def _get_port_pairs_from_proc_groups(self, proc_groups: ty.List[ProcGroup]): for src_port in src_ports: dst_ports = src_port.get_dst_ports() for dst_port in dst_ports: - if self._is_leaf_process_port(dst_port, processes): + if cls._is_leaf_process_port(dst_port, processes): port_pairs.append(PortPair(src=src_port, dst=dst_port)) return port_pairs @@ -111,9 +117,9 @@ def _is_leaf_process_port(dst_port, processes): dst_process = dst_port.process return True if dst_process in processes else False - def set_port_initializer( - self, port: AbstractPort, port_initializer: PortInitializer - ): + def set_port_initializer(self, + port: AbstractPort, + port_initializer: PortInitializer): if port in self._initializers_lookup.keys(): raise AssertionError( "An initializer for this port has already " "been assigned." @@ -125,3 +131,77 @@ def get_port_initializer(self, port): def has_port_initializer(self, port) -> bool: return port in self._initializers_lookup + + def write_to_cache(self, + cache_object: ty.Dict[ty.Any, ty.Any], + proc_to_procname_map: ty.Dict[AbstractProcess, str]): + cache_object["lmt_allocation"] = self._lmt_allocation_dict + + initializers_serializable: ty.List[ty.Tuple[str, str, + PortInitializer]] = [] + port: AbstractPort + pi: PortInitializer + for port, pi in self._initializers_lookup.items(): + procname = proc_to_procname_map[port.process] + if procname.startswith("Process_"): + msg = f"Unable to Cache. " \ + f"Please give unique names to every process. " \ + f"Violation Name: {procname=}" + raise Exception(msg) + + initializers_serializable.append((procname, port.name, pi)) + cache_object["initializers"] = initializers_serializable + + cm_serializable: ty.List[ty.Tuple[ty.Tuple[str, str], + ty.Tuple[str, str], + Payload]] = [] + port_pair: PortPair + payload: Payload + for port_pair, payload in self.items(): + src_port: AbstractPort = ty.cast(AbstractPort, port_pair.src) + dst_port: AbstractPort = ty.cast(AbstractPort, port_pair.dst) + src_proc_name: str = proc_to_procname_map[src_port.process] + src_port_info = (src_proc_name, src_port.name) + dst_proc_name: str = proc_to_procname_map[dst_port.process] + dst_port_info = (dst_proc_name, dst_port.name) + if src_proc_name.startswith("Process_") or \ + dst_proc_name.startswith("Process_"): + msg = f"Unable to Cache. " \ + f"Please give unique names to every process. " \ + f"Violation Name: {src_proc_name=} {dst_proc_name=}" + raise Exception(msg) + + cm_serializable.append((src_port_info, dst_port_info, payload)) + cache_object["channelmap_dict"] = cm_serializable + + def read_from_cache(self, + cache_object: ty.Dict[ty.Any, ty.Any], + procname_to_proc_map: ty.Dict[str, AbstractProcess]): + self._lmt_allocation_dict = cache_object["lmt_allocation"] + initializers_serializable = cache_object["initializers"] + cm_serializable = cache_object["channelmap_dict"] + + for procname, port_name, pi in initializers_serializable: + process: AbstractProcess = procname_to_proc_map[procname] + port: AbstractPort = getattr(process, port_name) + self._initializers_lookup[port] = pi + + src_port_info: ty.Tuple[str, str] + dst_port_info: ty.Tuple[str, str] + payload: Payload + for src_port_info, dst_port_info, payload in cm_serializable: + src_port_process: AbstractProcess = procname_to_proc_map[ + src_port_info[0]] + src: AbstractPort = getattr(src_port_process, + src_port_info[1]) + dst_port_process: AbstractProcess = procname_to_proc_map[ + dst_port_info[0]] + dst: AbstractPort = getattr(dst_port_process, + dst_port_info[1]) + for port_pair, pld in self.items(): + s, d = port_pair.src, port_pair.dst + if s.name == src.name and d.name == dst.name and \ + s.process.name == src_port_process.name and \ + d.process.name == dst_port_process.name: + pld.src_port_initializer = payload.src_port_initializer + pld.dst_port_initializer = payload.dst_port_initializer diff --git a/src/lava/magma/compiler/compiler.py b/src/lava/magma/compiler/compiler.py index 1daddb2ad..e447b488c 100644 --- a/src/lava/magma/compiler/compiler.py +++ b/src/lava/magma/compiler/compiler.py @@ -4,6 +4,8 @@ import itertools import logging +import os +import pickle # noqa: S403 # nosec import typing as ty from collections import OrderedDict, defaultdict @@ -219,6 +221,35 @@ def _compile_proc_groups( The global dict-like ChannelMap given as input but with values updated according to partitioning done by subcompilers. """ + procname_to_proc_map: ty.Dict[str, AbstractProcess] = {} + proc_to_procname_map: ty.Dict[AbstractProcess, str] = {} + for proc_group in proc_groups: + for p in proc_group: + procname_to_proc_map[p.name] = p + proc_to_procname_map[p] = p.name + + if self._compile_config.get("cache", False): + cache_dir = self._compile_config["cache_dir"] + if os.path.exists(os.path.join(cache_dir, "cache")): + with open(os.path.join(cache_dir, "cache"), "rb") \ + as cache_file: + cache_object = pickle.load(cache_file) # noqa: S301 # nosec + + proc_builders_values = cache_object["procname_to_proc_builder"] + proc_builders = {} + for proc_name, pb in proc_builders_values.items(): + proc = procname_to_proc_map[proc_name] + proc_builders[proc] = pb + pb.proc_params = proc.proc_params + + channel_map.read_from_cache(cache_object, procname_to_proc_map) + print(f"\nBuilders and Channel Map loaded from " + f"Cache {cache_dir}\n") + return proc_builders, channel_map + + # Get manual partitioning, if available + partitioning = self._compile_config.get("partitioning", None) + # Create the global ChannelMap that is passed between # SubCompilers to communicate about Channels between Processes. @@ -238,7 +269,8 @@ def _compile_proc_groups( subcompilers.append(pg_subcompilers) # Compile this ProcGroup. - self._compile_proc_group(pg_subcompilers, channel_map) + self._compile_proc_group(pg_subcompilers, channel_map, + partitioning) # Flatten the list of all SubCompilers. subcompilers = list(itertools.chain.from_iterable(subcompilers)) @@ -248,6 +280,28 @@ def _compile_proc_groups( subcompilers, channel_map ) + if self._compile_config.get("cache", False): + cache_dir = self._compile_config["cache_dir"] + os.makedirs(cache_dir, exist_ok=True) + cache_object = {} + # Validate All Processes are Named + procname_to_proc_builder = {} + for p, pb in proc_builders.items(): + if p.name in procname_to_proc_builder or \ + "Process_" in p.name: + msg = f"Unable to Cache. " \ + f"Please give unique names to every process. " \ + f"Violation Name: {p.name=}" + raise Exception(msg) + procname_to_proc_builder[p.name] = pb + pb.proc_params = None + cache_object["procname_to_proc_builder"] = procname_to_proc_builder + channel_map.write_to_cache(cache_object, proc_to_procname_map) + with open(os.path.join(cache_dir, "cache"), "wb") as cache_file: + pickle.dump(cache_object, cache_file) + for p, pb in proc_builders.items(): + pb.proc_params = p.proc_params + print(f"\nBuilders and Channel Map stored to Cache {cache_dir}\n") return proc_builders, channel_map @staticmethod @@ -353,7 +407,8 @@ def _create_subcompilers( @staticmethod def _compile_proc_group( - subcompilers: ty.List[AbstractSubCompiler], channel_map: ChannelMap + subcompilers: ty.List[AbstractSubCompiler], channel_map: ChannelMap, + partitioning: ty.Dict[str, ty.Dict] ) -> None: """For a given list of SubCompilers that have been initialized with the Processes of a single ProcGroup, iterate through the compilation @@ -369,6 +424,8 @@ def _compile_proc_group( channel_map : ChannelMap The global ChannelMap that contains information about Channels between Processes. + partitioning: ty.Dict + Optional manual mapping dictionary used by ncproc compiler. """ channel_map_prev = None @@ -381,7 +438,7 @@ def _compile_proc_group( for subcompiler in subcompilers: # Compile the Processes registered with each SubCompiler and # update the ChannelMap. - channel_map = subcompiler.compile(channel_map) + channel_map = subcompiler.compile(channel_map, partitioning) @staticmethod def _extract_proc_builders( @@ -713,8 +770,8 @@ def _create_runtime_service_builder( model_ids: ty.List[int] = [p.id for p in sync_domain.processes] rs_kwargs = { - "c_builders" : list(c_builders.values()), - "nc_builders" : list(nc_builders.values()) + "c_builders": list(c_builders.values()), + "nc_builders": list(nc_builders.values()) } if isinstance(run_cfg, AbstractLoihiHWRunCfg): rs_kwargs["callback_fxs"] = run_cfg.callback_fxs diff --git a/src/lava/magma/compiler/mapper.py b/src/lava/magma/compiler/mapper.py index e05939f89..b3ddb170f 100644 --- a/src/lava/magma/compiler/mapper.py +++ b/src/lava/magma/compiler/mapper.py @@ -162,6 +162,10 @@ def map_cores(self, executable: Executable, address.update(chips) break if len(address) > 1 and hasattr(var_model, "address"): + print('=' * 50) + print('Note to JOYESH from the future:') + print('Add logic to make multichip conv input work for YOLO.') + print('=' * 50) raise ValueError("Lava Compiler doesn't support port" "splitting currently. MultiChip " "Not Supported ") diff --git a/src/lava/magma/compiler/subcompilers/py/pyproc_compiler.py b/src/lava/magma/compiler/subcompilers/py/pyproc_compiler.py index d916a1e52..c5948a399 100644 --- a/src/lava/magma/compiler/subcompilers/py/pyproc_compiler.py +++ b/src/lava/magma/compiler/subcompilers/py/pyproc_compiler.py @@ -30,6 +30,7 @@ ImplicitVarPort, VarPort, ) +from lava.magma.core.process.ports.connection_config import ConnectionConfig from lava.magma.core.process.process import AbstractProcess from lava.magma.compiler.subcompilers.constants import SPIKE_BLOCK_CORE @@ -88,7 +89,8 @@ def __init__( super().__init__(proc_group, compile_config) self._spike_io_counter_offset: Offset = Offset() - def compile(self, channel_map: ChannelMap) -> ChannelMap: + def compile(self, channel_map: ChannelMap, + partitioning: ty.Dict = None) -> ChannelMap: return self._update_channel_map(channel_map) def __del__(self): @@ -189,7 +191,11 @@ def _create_inport_initializers( pi.embedded_counters = \ np.arange(counter_start_idx, counter_start_idx + num_counters, dtype=np.int32) - pi.connection_config = list(port.connection_configs.values())[0] + if port.connection_configs.values(): + conn_config = list(port.connection_configs.values())[0] + else: + conn_config = ConnectionConfig() + pi.connection_config = conn_config port_initializers.append(pi) self._tmp_channel_map.set_port_initializer(port, pi) else: @@ -209,7 +215,7 @@ def _create_outport_initializers( self, process: AbstractProcess ) -> ty.List[PortInitializer]: port_initializers = [] - for port in list(process.out_ports): + for k, port in enumerate(list(process.out_ports)): pi = PortInitializer( port.name, port.shape, @@ -218,6 +224,11 @@ def _create_outport_initializers( self._compile_config["pypy_channel_size"], port.get_incoming_transform_funcs(), ) + if port.connection_configs.values(): + conn_config = list(port.connection_configs.values())[k] + else: + conn_config = ConnectionConfig() + pi.connection_config = conn_config port_initializers.append(pi) self._tmp_channel_map.set_port_initializer(port, pi) return port_initializers diff --git a/src/lava/magma/compiler/var_model.py b/src/lava/magma/compiler/var_model.py index e33f3fbd9..94097e71e 100644 --- a/src/lava/magma/compiler/var_model.py +++ b/src/lava/magma/compiler/var_model.py @@ -269,6 +269,14 @@ class NcSpikeIOVarModel(NcVarModel): interface: SpikeIOInterface = SpikeIOInterface.ETHERNET spike_io_port: SpikeIOPort = SpikeIOPort.ETHERNET spike_io_mode: SpikeIOMode = SpikeIOMode.TIME_COMPARE + ethernet_chip_id: ty.Optional[ty.Tuple[int, int, int]] = None + ethernet_chip_idx: ty.Optional[int] = None decode_config: ty.Optional[DecodeConfig] = None time_compare: ty.Optional[TimeCompare] = None spike_encoder: ty.Optional[SpikeEncoder] = None + + +@dataclass +class NcConvSpikeInVarModel(NcSpikeIOVarModel): + # Tuple will be in the order of [atom_paylod, atom_axon, addr_idx] + region_map: ty.List[ty.List[ty.Tuple[int, int, int]]] = None diff --git a/src/lava/magma/core/learning/utils.py b/src/lava/magma/core/learning/utils.py index 480860397..f8e808d44 100644 --- a/src/lava/magma/core/learning/utils.py +++ b/src/lava/magma/core/learning/utils.py @@ -29,23 +29,24 @@ def stochastic_round(values: np.ndarray, return (values + (random_numbers < probabilities).astype(int)).astype(int) -def apply_mask(int_number: int, nb_bits: int) -> int: +def apply_mask(item: ty.Union[np.ndarray, int], nb_bits: int) \ + -> ty.Union[np.ndarray, int]: """Get nb_bits least-significant bits. Parameters ---------- - int_number : int - Integer number. + item : np.ndarray or int + Item to apply mask to. nb_bits : int Number of LSBs to keep. Returns ---------- - result : int + result : np.ndarray or int Least-significant bits. """ mask = ~(~0 << nb_bits) - return int_number & mask + return item & mask def float_to_literal(learning_parameter: float) -> str: diff --git a/src/lava/magma/core/model/py/connection.py b/src/lava/magma/core/model/py/connection.py index dfa33c440..7944f5406 100644 --- a/src/lava/magma/core/model/py/connection.py +++ b/src/lava/magma/core/model/py/connection.py @@ -441,8 +441,8 @@ def _update_synaptic_variable_random(self) -> None: pass def _update_dependencies(self) -> None: - self.x0[self.tx > 0] = True - self.y0[self.ty > 0] = True + self.x0 = self.tx > 0 + self.y0 = self.ty > 0 @abstractmethod def _compute_trace_histories(self) -> typing.Tuple[np.ndarray, np.ndarray]: diff --git a/src/lava/magma/core/model/py/model.py b/src/lava/magma/core/model/py/model.py index 40235d4e1..ec6c252bc 100644 --- a/src/lava/magma/core/model/py/model.py +++ b/src/lava/magma/core/model/py/model.py @@ -759,6 +759,10 @@ def run_async(self) -> None: if py_loihi_model.post_guard(self): py_loihi_model.run_post_mgmt(self) self.time_step += 1 + # self.advance_to_time_step(self.time_step) + for port in self.py_ports: + if isinstance(port, PyOutPort): + port.advance_to_time_step(self.time_step) py_async_model = type( name, diff --git a/src/lava/magma/core/process/ports/connection_config.py b/src/lava/magma/core/process/ports/connection_config.py index 86b0a6d3d..2b5aca897 100644 --- a/src/lava/magma/core/process/ports/connection_config.py +++ b/src/lava/magma/core/process/ports/connection_config.py @@ -14,6 +14,7 @@ # expressly stated in the License. from dataclasses import dataclass from enum import IntEnum, Enum +import typing as ty class SpikeIOInterface(IntEnum): @@ -54,3 +55,6 @@ class ConnectionConfig: spike_io_mode: SpikeIOMode = SpikeIOMode.TIME_COMPARE num_time_buckets: int = 1 << 16 ethernet_mac_address: str = "0x90e2ba01214c" + loihi_mac_address: str = "0x0015edbeefed" + ethernet_chip_id: ty.Optional[ty.Tuple[int, int, int]] = None + ethernet_chip_idx: ty.Optional[int] = None diff --git a/src/lava/magma/core/process/ports/ports.py b/src/lava/magma/core/process/ports/ports.py index be16cf63a..986442f48 100644 --- a/src/lava/magma/core/process/ports/ports.py +++ b/src/lava/magma/core/process/ports/ports.py @@ -432,6 +432,17 @@ class OutPort(AbstractIOPort, AbstractSrcPort): sub processes. """ + def __init__(self, shape: ty.Tuple[int, ...]): + super().__init__(shape) + self.external_pipe_flag = False + self.external_pipe_buffer_size = 64 + + def flag_external_pipe(self, buffer_size=None): + self.external_pipe_flag = True + + if buffer_size is not None: + self.external_pipe_buffer_size = buffer_size + def connect( self, ports: ty.Union["AbstractIOPort", ty.List["AbstractIOPort"]], @@ -493,6 +504,15 @@ def __init__( super().__init__(shape) self._reduce_op = reduce_op + self.external_pipe_flag = False + self.external_pipe_buffer_size = 64 + + def flag_external_pipe(self, buffer_size=None): + self.external_pipe_flag = True + + if buffer_size is not None: + self.external_pipe_buffer_size = buffer_size + def connect(self, ports: ty.Union["InPort", ty.List["InPort"]], connection_configs: ty.Optional[ConnectionConfigs] = None): diff --git a/src/lava/magma/runtime/message_infrastructure/multiprocessing.py b/src/lava/magma/runtime/message_infrastructure/multiprocessing.py index 7c9e5aed9..5e3fd6b00 100644 --- a/src/lava/magma/runtime/message_infrastructure/multiprocessing.py +++ b/src/lava/magma/runtime/message_infrastructure/multiprocessing.py @@ -113,11 +113,13 @@ def start(self): def build_actor(self, target_fn: ty.Callable, builder: ty.Union[ ty.Dict['AbstractProcess', 'PyProcessBuilder'], ty.Dict[ - SyncDomain, 'RuntimeServiceBuilder']]) -> ty.Any: + SyncDomain, 'RuntimeServiceBuilder']], + exception_q: mp.Queue = None) -> ty.Any: """Given a target_fn starts a system (os) process""" system_process = SystemProcess(target=target_fn, args=(), - kwargs={"builder": builder}) + kwargs={"builder": builder, + "exception_q": exception_q}) system_process.start() self._actors.append(system_process) return system_process diff --git a/src/lava/magma/runtime/runtime.py b/src/lava/magma/runtime/runtime.py index d5dde5a92..507def566 100644 --- a/src/lava/magma/runtime/runtime.py +++ b/src/lava/magma/runtime/runtime.py @@ -26,7 +26,7 @@ if ty.TYPE_CHECKING: from lava.magma.core.process.process import AbstractProcess from lava.magma.compiler.channels.pypychannel import CspRecvPort, CspSendPort, \ - CspSelector + CspSelector, PyPyChannel from lava.magma.compiler.builders.channel_builder import ( ChannelBuilderMp, RuntimeChannelBuilderMp, ServiceChannelBuilderMp, ChannelBuilderPyNc) @@ -38,10 +38,11 @@ ChannelType from lava.magma.compiler.executable import Executable from lava.magma.compiler.node import NodeConfig -from lava.magma.core.process.ports.ports import create_port_id +from lava.magma.core.process.ports.ports import create_port_id, InPort, OutPort from lava.magma.core.run_conditions import (AbstractRunCondition, RunContinuous, RunSteps) from lava.magma.compiler.channels.watchdog import WatchdogManagerInterface +from multiprocessing import Queue """Defines a Runtime which takes a lava executable and a pluggable message passing infrastructure (for instance multiprocessing+shared memory or ray in @@ -94,13 +95,15 @@ def target_fn(*args, **kwargs): """ try: builder = kwargs.pop("builder") + exception_q = kwargs.pop('exception_q') actor = builder.build() + # No exception occured + exception_q.put(None) actor.start(*args, **kwargs) except Exception as e: - print("Encountered Fatal Exception: " + str(e)) - print("Traceback: ") - print(traceback.format_exc()) - raise e + e.trace = traceback.format_exc() + exception_q.put(e) + raise(e) class Runtime: @@ -134,6 +137,7 @@ def __init__(self, self.num_steps: int = 0 self._watchdog_manager = None + self.exception_q = [] def __del__(self): """On destruction, terminate Runtime automatically to @@ -160,6 +164,15 @@ def initialize(self, node_cfg_idx: int = 0): self._build_processes() self._build_runtime_services() self._start_ports() + + # Check if any exception was thrown + for q in self.exception_q: + e = q.get() + if e: + print(str(e), e.trace) + raise(e) + del self.exception_q + self.log.debug("Runtime Initialization Complete") self._is_initialized = True @@ -293,17 +306,64 @@ def _build_processes(self): if isinstance(proc_builder, PyProcessBuilder): # Assign current Runtime to process proc._runtime = self + exception_q = Queue() + self.exception_q.append(exception_q) + + # Create any external pypychannels + self._create_external_channels(proc, proc_builder) + self._messaging_infrastructure.build_actor(target_fn, - proc_builder) + proc_builder, + exception_q) def _build_runtime_services(self): """Builds the runtime services""" runtime_service_builders = self._executable.runtime_service_builders if self._executable.runtime_service_builders: for _, rs_builder in runtime_service_builders.items(): + self.exception_q.append(Queue()) self._messaging_infrastructure. \ build_actor(target_fn, - rs_builder) + rs_builder, + self.exception_q[-1]) + + def _create_external_channels(self, + proc: AbstractProcess, + proc_builder: AbstractProcessBuilder): + """Creates a csp channel which can be connected to/from a + non-procss/Lava python environment. This enables I/O to Lava from + external sources.""" + for name, py_port in proc_builder.py_ports.items(): + port = getattr(proc, name) + + if port.external_pipe_flag: + if isinstance(port, InPort): + pypychannel = PyPyChannel( + message_infrastructure=self._messaging_infrastructure, + src_name="src", + dst_name=name, + shape=py_port.shape, + dtype=py_port.d_type, + size=port.external_pipe_buffer_size) + + proc_builder.set_csp_ports([pypychannel.dst_port]) + + port.external_pipe_csp_send_port = pypychannel.src_port + port.external_pipe_csp_send_port.start() + + if isinstance(port, OutPort): + pypychannel = PyPyChannel( + message_infrastructure=self._messaging_infrastructure, + src_name=name, + dst_name="dst", + shape=py_port.shape, + dtype=py_port.d_type, + size=port.external_pipe_buffer_size) + + proc_builder.set_csp_ports([pypychannel.src_port]) + + port.external_pipe_csp_recv_port = pypychannel.dst_port + port.external_pipe_csp_recv_port.start() def _get_resp_for_run(self): """ diff --git a/src/lava/networks/gradedvecnetwork.py b/src/lava/networks/gradedvecnetwork.py new file mode 100644 index 000000000..abf163b7d --- /dev/null +++ b/src/lava/networks/gradedvecnetwork.py @@ -0,0 +1,324 @@ +# Copyright (C) 2022-23 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +import typing as ty + +from lava.proc.graded.process import InvSqrt +from lava.proc.graded.process import NormVecDelay +from lava.proc.sparse.process import Sparse +from lava.proc.dense.process import Dense +from lava.proc.prodneuron.process import ProdNeuron +from lava.proc.graded.process import GradedVec as GradedVecProc +from lava.proc.lif.process import LIF +from lava.proc.io import sink, source + +from .network import Network, AlgebraicVector, AlgebraicMatrix + + +class InputVec(AlgebraicVector): + """InputVec + Simple input vector. Adds algebraic syntax to RingBuffer + + Parameters + ---------- + vec : np.ndarray + NxM array of input values. Input will repeat every M steps. + exp : int, optional + Set the fixed point base value + loihi2 : bool, optional + Flag to create the adapters for loihi 2. + """ + + def __init__(self, + vec: np.ndarray, + loihi2: ty.Optional[bool] = False, + exp: ty.Optional[int] = 0, + **kwargs) -> None: + + self.loihi2 = loihi2 + self.shape = np.atleast_2d(vec).shape + self.exp = exp + + # Convert it to fixed point base + vec *= 2**self.exp + + self.inport_plug = source.RingBuffer(data=np.atleast_2d(vec)) + + if self.loihi2: + from lava.proc import embedded_io as eio + self.inport_adapter = eio.spike.PyToNxAdapter( + shape=(self.shape[0],), + num_message_bits=24) + self.inport_plug.s_out.connect(self.inport_adapter.inp) + self.out_port = self.inport_adapter.out + + else: + self.out_port = self.inport_plug.s_out + + def __lshift__(self, other): + # Maybe this could be done with a numpy array and call set_data? + return NotImplemented + + +class OutputVec(Network): + """OutputVec + Records spike output. Adds algebraic syntax to RingBuffer + + Parameters + ---------- + shape : tuple(int) + shape of the output to record + buffer : int, optional + length of the recording. + (buffer is overwritten if shorter than sim time). + loihi2 : bool, optional + Flag to create the adapters for loihi 2. + num_message_bits : int + size of output message. ("0" is for unary spike event). + """ + + def __init__(self, + shape: ty.Tuple[int, ...], + buffer: int = 1, + loihi2: ty.Optional[bool] = False, + num_message_bits: ty.Optional[int] = 24, + **kwargs) -> None: + + self.shape = shape + self.buffer = buffer + self.loihi2 = loihi2 + self.num_message_bits = num_message_bits + + self.outport_plug = sink.RingBuffer( + shape=self.shape, buffer=self.buffer, **kwargs) + + if self.loihi2: + from lava.proc import embedded_io as eio + self.outport_adapter = eio.spike.NxToPyAdapter( + shape=self.shape, num_message_bits=self.num_message_bits) + self.outport_adapter.out.connect(self.outport_plug.a_in) + self.in_port = self.outport_adapter.inp + else: + self.in_port = self.outport_plug.a_in + + def get_data(self): + return (self.outport_plug.data.get().astype(np.int32) << 8) >> 8 + + +class LIFVec(AlgebraicVector): + """LIFVec + Network wrapper to LIF neuron. + + Parameters + ---------- + See lava.proc.lif.process.LIF + """ + + def __init__(self, **kwargs): + self.main = LIF(**kwargs) + + self.in_port = self.main.a_in + self.out_port = self.main.s_out + + +class GradedVec(AlgebraicVector): + """GradedVec + Simple graded threshold vector with no dynamics. + + Parameters + ---------- + shape : tuple(int) + Number and topology of neurons. + vth : int, optional + Threshold for spiking. + exp : int, optional + Fixed point base of the vector. + """ + + def __init__(self, + shape: ty.Tuple[int, ...], + vth: int = 10, + exp: int = 0, + **kwargs): + + self.shape = shape + self.vth = vth + self.exp = exp + + self.main = GradedVecProc(shape=self.shape, vth=self.vth, exp=self.exp) + self.in_port = self.main.a_in + self.out_port = self.main.s_out + + super().__init__() + + def __mul__(self, other): + if isinstance(other, GradedVec): + # Create the product network + prod_layer = ProductVec(shape=self.shape, vth=1, exp=self.exp) + + weightsI = np.eye(self.shape[0]) + + weights_A = GradedSparse(weights=weightsI) + weights_B = GradedSparse(weights=weightsI) + weights_out = GradedSparse(weights=weightsI) + + prod_layer << (weights_A @ self, weights_B @ other) + weights_out @ prod_layer + return weights_out + else: + return NotImplemented + + +class ProductVec(AlgebraicVector): + """ProductVec + + Neuron that will multiply values on two input channels. + + Parameters + ---------- + shape : tuple(int) + Number and topology of neurons. + vth : int + Threshold for spiking. + exp : int + Fixed point base of the vector. + """ + + def __init__(self, + shape: ty.Tuple[int, ...], + vth: ty.Optional[int] = 10, + exp: ty.Optional[int] = 0, + **kwargs): + self.shape = shape + self.vth = vth + self.exp = exp + + self.main = ProdNeuron(shape=self.shape, vth=self.vth, exp=self.exp) + + self.in_port = self.main.a_in1 + self.in_port2 = self.main.a_in2 + + self.out_port = self.main.s_out + + def __lshift__(self, other): + # We're going to override the behavior here, + # since there are two ports the API idea is: + # prod_layer << (conn1, conn2) + if isinstance(other, (list, tuple)): + # It should be only length 2, and a Network object, + # TODO: add checks + other[0].out_port.connect(self.in_port) + other[1].out_port.connect(self.in_port2) + else: + return NotImplemented + + +class GradedDense(AlgebraicMatrix): + """GradedDense + Network wrapper for Dense. Adds algebraic syntax to Dense. + + Parameters + ---------- + See lava.proc.dense.process.Dense + + weights : numpy.ndarray + Weight matrix expressed as floating point. Weights will be automatically + reconfigured to fixed point (may lead to changes due to rounding). + exp : int, optional + Fixed point base of the weight (reconfigures weights/weight_exp). + """ + + def __init__(self, + weights: np.ndarray, + exp: int = 7, + **kwargs): + self.exp = exp + + # Adjust the weights to the fixed point + w = weights * 2 ** self.exp + + self.main = Dense(weights=w, + num_message_bits=24, + num_weight_bits=8, + weight_exp=-self.exp) + + self.in_port = self.main.s_in + self.out_port = self.main.a_out + + +class GradedSparse(AlgebraicMatrix): + """GradedSparse + Network wrapper for Sparse. Adds algebraic syntax to Sparse. + + Parameters + ---------- + See lava.proc.sparse.process.Sparse + + weights : numpy.ndarray + Weight matrix expressed as floating point. Weights will be automatically + reconfigured to fixed point (may lead to changes due to rounding). + exp : int, optional + Fixed point base of the weight (reconfigures weights/weight_exp). + """ + + def __init__(self, + weights: np.ndarray, + exp: int = 7, + **kwargs): + + self.exp = exp + + # Adjust the weights to the fixed point + w = weights * 2 ** self.exp + self.main = Sparse(weights=w, + num_message_bits=24, + num_weight_bits=8, + weight_exp=-self.exp) + + self.in_port = self.main.s_in + self.out_port = self.main.a_out + + +class NormalizeNet(AlgebraicVector): + """NormalizeNet + Creates a layer for normalizing vector inputs + + Parameters + ---------- + shape : tuple(int) + Number and topology of neurons. + exp : int + Fixed point base of the vector. + """ + + def __init__(self, + shape: ty.Tuple[int, ...], + exp: ty.Optional[int] = 12, + **kwargs): + self.shape = shape + self.fpb = exp + + vec_to_fpinv_w = np.ones((1, self.shape[0])) + fpinv_to_vec_w = np.ones((self.shape[0], 1)) + weight_exp = 0 + + self.vfp_dense = Dense(weights=vec_to_fpinv_w, + num_message_bits=24, + weight_exp=-weight_exp) + self.fpv_dense = Dense(weights=fpinv_to_vec_w, + num_message_bits=24, + weight_exp=-weight_exp) + + self.main = NormVecDelay(shape=self.shape, vth=1, + exp=self.fpb) + self.fp_inv_neuron = InvSqrt(shape=(1,), fp_base=self.fpb) + + self.main.s2_out.connect(self.vfp_dense.s_in) + self.vfp_dense.a_out.connect(self.fp_inv_neuron.a_in) + self.fp_inv_neuron.s_out.connect(self.fpv_dense.s_in) + self.fpv_dense.a_out.connect(self.main.a_in2) + + self.in_port = self.main.a_in1 + self.out_port = self.main.s_out diff --git a/src/lava/networks/network.py b/src/lava/networks/network.py new file mode 100644 index 000000000..8e9d1e5e1 --- /dev/null +++ b/src/lava/networks/network.py @@ -0,0 +1,154 @@ +# Copyright (C) 2022-23 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +import typing as ty +from scipy.sparse import csr_matrix + +from lava.magma.core.process.ports.ports import InPort, OutPort +from lava.magma.core.process.process import AbstractProcess + + +class NetworkList(list): + """NetworkList + This is a list subclass to keep track of Network objects that + are added using the '+' operator. + """ + + def __init__(self, iterable): + super().__init__(iterable) + + +class Network: + """Network + Abstract Network object. + + Networks contain other networks and lava processes. + """ + + in_port: InPort + out_port: OutPort + main: AbstractProcess + + def run(self, **kwargs): + self.main.run(**kwargs) + + def stop(self, **kwargs): + self.main.stop(**kwargs) + + def __lshift__(self, + other): + # Self-referential type hint is causing a NameError + # other: ty.Union[Network, NetworkList]): + """ + Operator overload of "<<" to connect Network objects. + + EPF: note that the precedence could matter if we include more + operators. We want this assignment operator to have lowest + precedence, which "<<" is lower than "+", so it works. However, it + is higher than i.e. "^" which would not work. Comparisons have even + lower precedence, "<=" could be better. + """ + if isinstance(other, Network): + other.out_port.connect(self.in_port) + return self + elif isinstance(other, NetworkList): + for o in other: + self << o + return self + else: + return NotImplemented + + def __add__(self, + other): + # Self-referential typing is causing a NameError + # other: ty.Union[Network, NetworkList]): + """ + Operator overload of "+" to act as summation in algebraic syntax. + """ + if isinstance(other, Network): + return NetworkList([self, other]) + elif isinstance(other, NetworkList): + other.append(self) + return other + else: + return NotImplemented + # When chaining operations this is used for [weights1, weights2] + weights3 + __radd__ = __add__ + + +class AlgebraicVector(Network): + """AlgebraicVector + Provides vector operator syntax for Networks. + """ + + def __lshift__(self, + other): + # Self-referential typing is causing a NameError + # other: ty.Union[AlgebraicVector, Network, NetworkList]): + """ + Operator overload of "<<" to connect AlgebraicVector objects. + """ + + if isinstance(other, AlgebraicVector): + # If a vector is connected to another vector, an Identity + # connection is generated and the two procs are connected. + + # This import statement needs to be here to avoid a circular + # import error + from lava.networks.gradedvecnetwork import GradedSparse + weightsI = csr_matrix(np.eye(np.prod(self.shape))) + I_syn = GradedSparse(weights=weightsI) + other.out_port.connect(I_syn.in_port) + I_syn.out_port.connect(self.in_port) + return self + + elif isinstance(other, Network): + # This will take care of the standard weights to neurons. + other.out_port.connect(self.in_port) + return self + elif isinstance(other, NetworkList): + # When using the plus operator to add + for o in other: + self << o + return self + else: + return NotImplemented + + +class AlgebraicMatrix(Network): + """AlgebraicMatrix + Provides matrix operator syntax for Networks. + """ + + def __matmul__(self, + other): + # Self-referential typing is causing a NameError + # other: AlgebraicVector): + """ + Operator overload of "@" to form matrix-vector product. + """ + if isinstance(other, AlgebraicVector): + other.out_port.connect(self.in_port) + return self + else: + return NotImplemented + + def __mul__(self, + other): + # Self-referential typing is causing a NameError + # other: AlgebraicMatrix): + """ + Operator overload of "*" to for multiplication. + """ + if isinstance(other, AlgebraicMatrix): + from lava.networks.gradedvecnetwork import ProductVec + # How to pass in exp? + prod_layer = ProductVec(shape=self.shape, vth=1, exp=0) + + prod_layer << (self, other) + + return prod_layer + else: + return NotImplemented diff --git a/src/lava/networks/resfire.py b/src/lava/networks/resfire.py new file mode 100644 index 000000000..7712a4649 --- /dev/null +++ b/src/lava/networks/resfire.py @@ -0,0 +1,45 @@ +# Copyright (C) 2022-23 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +from .network import AlgebraicVector +from lava.proc.resfire.process import RFZero + + +class ResFireVec(AlgebraicVector): + """ + Network wrapper for resonate-and-fire neurons + """ + + def __init__(self, **kwargs): + self.uth = kwargs.pop('uth', 10) + self.shape = kwargs.pop('shape', (1,)) + self.freqs = kwargs.pop('freqs', np.array([10])) + self.decay_tau = kwargs.pop('decay_tau', np.array([1])) + self.dt = kwargs.pop('dt', 0.001) + + self.freqs = np.array(self.freqs) + self.decay_tau = np.array(self.decay_tau) + + self.main = RFZero(shape=self.shape, uth=self.uth, + freqs=self.freqs, decay_tau=self.decay_tau, + dt=self.dt) + + self.in_port = self.main.u_in + self.in_port2 = self.main.v_in + + self.out_port = self.main.s_out + + def __lshift__(self, other): + # We're going to override the behavior here + # since theres two ports the API idea is: + # rf_layer << (conn1, conn2) + if isinstance(other, (list, tuple)): + # it should be only length 2, and a Network object, + # add checks + other[0].out_port.connect(self.in_port) + other[1].out_port.connect(self.in_port2) + else: + # in this case we will just connect to in_port + super().__lshift__(other) diff --git a/src/lava/proc/atrlif/models.py b/src/lava/proc/atrlif/models.py new file mode 100644 index 000000000..bb2aa1c9d --- /dev/null +++ b/src/lava/proc/atrlif/models.py @@ -0,0 +1,267 @@ +# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024 Jannik Luboeinski +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol +from lava.magma.core.model.py.ports import PyInPort, PyOutPort +from lava.magma.core.model.py.type import LavaPyType +from lava.magma.core.resources import CPU +from lava.magma.core.decorator import implements, requires, tag +from lava.magma.core.model.py.model import PyLoihiProcessModel + +from lava.proc.atrlif.process import ATRLIF + + +@implements(proc=ATRLIF, protocol=LoihiProtocol) +@requires(CPU) +@tag("floating_pt") +class PyATRLIFModelFloat(PyLoihiProcessModel): + """ + Implementation of Adaptive Threshold and Refractoriness Leaky-Integrate- + and-Fire neuron process in floating-point precision. This short and simple + ProcessModel can be used for quick algorithmic prototyping, without + engaging with the nuances of a fixed-point implementation. + """ + a_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, float) + s_out = None + i: np.ndarray = LavaPyType(np.ndarray, float) + v: np.ndarray = LavaPyType(np.ndarray, float) + theta: np.ndarray = LavaPyType(np.ndarray, float) + r: np.ndarray = LavaPyType(np.ndarray, float) + s: np.ndarray = LavaPyType(np.ndarray, bool) + bias_mant: np.ndarray = LavaPyType(np.ndarray, float) + bias_exp: np.ndarray = LavaPyType(np.ndarray, float) + delta_i: float = LavaPyType(float, float) + delta_v: float = LavaPyType(float, float) + delta_theta: float = LavaPyType(float, float) + delta_r: float = LavaPyType(float, float) + theta_0: float = LavaPyType(float, float) + theta_step: float = LavaPyType(float, float) + s_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) + + def __init__(self, proc_params): + super(PyATRLIFModelFloat, self).__init__(proc_params) + + def subthr_dynamics(self, activation_in: np.ndarray): + """ + Sub-threshold dynamics for the model: + i[t] = (1-delta_i)*i[t-1] + x[t] + v[t] = (1-delta_v)*v[t-1] + i[t] + bias_mant + theta[t] = (1-delta_theta)*(theta[t-1] - theta_0) + theta_0 + r[t] = (1-delta_r)*r[t-1] + """ + self.i[:] = (1 - self.delta_i) * self.i + activation_in + self.v[:] = (1 - self.delta_v) * self.v + self.i + self.bias_mant + self.theta[:] = (1 - self.delta_theta) * (self.theta - self.theta_0) \ + + self.theta_0 + self.r[:] = (1 - self.delta_r) * self.r + + def post_spike(self, spike_vector: np.ndarray): + """ + Post spike/refractory behavior: + r[t] = r[t] + 2*theta[t] + theta[t] = theta[t] + theta_step + """ + # For spiking neurons, set new values for refractory state and + # threshold + r_spiking = self.r[spike_vector] + theta_spiking = self.theta[spike_vector] + self.r[spike_vector] = r_spiking + 2 * theta_spiking + self.theta[spike_vector] = theta_spiking + self.theta_step + + def run_spk(self): + """ + The run function that performs the actual computation. Processes spike + events that occur if (v[t] - r[t]) >= theta[t]. + """ + # Receive synaptic input + a_in_data = self.a_in.recv() + + # Perform the sub-threshold and spike computations + self.subthr_dynamics(activation_in=a_in_data) + self.s[:] = (self.v - self.r) >= self.theta + self.post_spike(spike_vector=self.s) + self.s_out.send(self.s) + + +@implements(proc=ATRLIF, protocol=LoihiProtocol) +@requires(CPU) +@tag("bit_accurate_loihi", "fixed_pt") +class PyATRLIFModelFixed(PyLoihiProcessModel): + """ + Implementation of Adaptive Threshold and Refractoriness Leaky-Integrate- + and-Fire neuron process in fixed-point precision, bit-by-bit mimicking the + fixed-point computation behavior of Loihi 2. + """ + a_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, np.int16, precision=16) + i: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=24) + v: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=24) + theta: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=24) + r: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=24) + s: np.ndarray = LavaPyType(np.ndarray, bool) + bias_mant: np.ndarray = LavaPyType(np.ndarray, np.int16, precision=13) + bias_exp: np.ndarray = LavaPyType(np.ndarray, np.int16, precision=3) + delta_i: int = LavaPyType(int, np.uint16, precision=12) + delta_v: int = LavaPyType(int, np.uint16, precision=12) + delta_theta: int = LavaPyType(int, np.uint16, precision=12) + delta_r: int = LavaPyType(int, np.uint16, precision=12) + theta_0: int = LavaPyType(int, np.uint16, precision=12) + theta_step: int = LavaPyType(int, np.uint16, precision=12) + s_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, np.int32, precision=24) + + def __init__(self, proc_params): + super(PyATRLIFModelFixed, self).__init__(proc_params) + + # The `ds_offset` constant enables setting decay constant values to + # exact 4096 = 2**12. Without it, the range of 12-bit unsigned + # `delta_i` is 0 to 4095. + self.ds_offset = 1 + self.isthrscaled = False + self.effective_bias = 0 + # State variables i and v are 24 bits wide + self.iv_bitwidth = 24 + self.max_iv_val = 2**(self.iv_bitwidth - 1) + # Decays need an MSB alignment by 12 bits + self.decay_shift = 12 + self.decay_unity = 2**self.decay_shift + # Threshold and incoming activation are MSB-aligned by 6 bits + self.theta_unity = 2**6 + self.act_unity = 2**6 + + def subthr_dynamics(self, activation_in: np.ndarray): + """ + Sub-threshold dynamics for the model: + i[t] = (1-delta_i)*i[t-1] + x[t] + v[t] = (1-delta_v)*v[t-1] + i[t] + bias_mant + theta[t] = (1-delta_theta)*(theta[t-1] - theta_0) + theta_0 + r[t] = (1-delta_r)*r[t-1] + """ + # Update current + # -------------- + # Multiplication is done for left shifting, offset is added + decay_const_i = self.delta_i * self.decay_unity + self.ds_offset + # Below, i is promoted to int64 to avoid overflow of the product + # between i and decay constant beyond int32. + # Subsequent right shift by 12 brings us back within 24-bits (and + # hence, within 32-bits). + i_decayed = np.int64(self.i * (self.decay_unity - decay_const_i)) + i_decayed = np.sign(i_decayed) * np.right_shift( + np.abs(i_decayed), self.decay_shift + ) + # Multiplication is done for left shifting (to account for MSB + # alignment done by the hardware). + activation_in = activation_in * self.act_unity + # Add synaptic input to decayed current + i_updated = np.int32(i_decayed + activation_in) + # Check if value of current is within bounds of 24-bit. Overflows are + # handled by wrapping around modulo. + # 2 ** 23. E.g., (2 ** 23) + k becomes k and -(2**23 + k) becomes -k + wrapped_curr = np.where( + i_updated > self.max_iv_val, + i_updated - 2 * self.max_iv_val, + i_updated, + ) + wrapped_curr = np.where( + wrapped_curr <= -self.max_iv_val, + i_updated + 2 * self.max_iv_val, + wrapped_curr, + ) + self.i[:] = wrapped_curr + + # Update voltage (proceeding similar to current update) + # ----------------------------------------------------- + decay_const_v = self.delta_v * self.decay_unity + neg_voltage_limit = -np.int32(self.max_iv_val) + 1 + pos_voltage_limit = np.int32(self.max_iv_val) - 1 + v_decayed = np.int64(self.v) * np.int64(self.decay_unity + - decay_const_v) + v_decayed = np.sign(v_decayed) * np.right_shift( + np.abs(v_decayed), self.decay_shift + ) + v_updated = np.int32(v_decayed + self.i + self.effective_bias) + self.v[:] = np.clip(v_updated, neg_voltage_limit, pos_voltage_limit) + + # Update threshold (proceeding similar to current update) + # ------------------------------------------------------- + decay_const_theta = self.delta_theta * self.decay_unity + theta_diff_decayed = np.int64(self.theta - self.theta_0) * \ + np.int64(self.decay_unity - decay_const_theta) + theta_diff_decayed = np.sign(theta_diff_decayed) * np.right_shift( + np.abs(theta_diff_decayed), self.decay_shift + ) + self.theta[:] = np.int32(theta_diff_decayed) + self.theta_0 + # TODO do clipping here? + + # Update refractoriness (decaying similar to current) + # --------------------------------------------------- + decay_const_r = self.delta_r * self.decay_unity + r_decayed = np.int64(self.r) * np.int64(self.decay_unity + - decay_const_r) + r_decayed = np.sign(r_decayed) * np.right_shift( + np.abs(r_decayed), self.decay_shift + ) + self.r[:] = np.int32(r_decayed) + # TODO do clipping here? + + def scale_bias(self): + """ + Scale bias with bias exponent by taking into account sign of the + exponent. + """ + # Create local copy of `bias_mant` with promoted dtype to prevent + # overflow when applying shift of `bias_exp`. + bias_mant = self.bias_mant.copy().astype(np.int32) + self.effective_bias = np.where( + self.bias_exp >= 0, + np.left_shift(bias_mant, self.bias_exp), + np.right_shift(bias_mant, -self.bias_exp), + ) + + def scale_threshold(self): + """ + Scale threshold according to the way Loihi hardware scales it. In Loihi + hardware, threshold is left-shifted by 6-bits to MSB-align it with + other state variables of higher precision. + """ + # Multiplication is done for left shifting + self.theta_0 = np.int32(self.theta_0 * self.theta_unity) + self.theta = np.full(self.theta.shape, self.theta_0) + self.theta_step = np.int32(self.theta_step * self.theta_unity) + self.isthrscaled = True + + def post_spike(self, spike_vector: np.ndarray): + """ + Post spike/refractory behavior: + r[t] = r[t] + 2*theta[t] + theta[t] = theta[t] + theta_step + """ + # For spiking neurons, set new values for refractory state and + # threshold. + r_spiking = self.r[spike_vector] + theta_spiking = self.theta[spike_vector] + self.r[spike_vector] = r_spiking + 2 * theta_spiking + self.theta[spike_vector] = theta_spiking + self.theta_step + + def run_spk(self): + """ + The run function that performs the actual computation. Processes spike + events that occur if (v[t] - r[t]) >= theta[t]. + """ + # Receive synaptic input + a_in_data = self.a_in.recv() + + # Compute effective bias + self.scale_bias() + + # Compute scaled threshold-related variables only once, not every + # timestep (has to be done once after object construction). + if not self.isthrscaled: + self.scale_threshold() + + # Perform the sub-threshold and spike computations + self.subthr_dynamics(activation_in=a_in_data) + self.s[:] = (self.v - self.r) >= self.theta + self.post_spike(spike_vector=self.s) + self.s_out.send(self.s) diff --git a/src/lava/proc/atrlif/process.py b/src/lava/proc/atrlif/process.py new file mode 100644 index 000000000..1f5bf8152 --- /dev/null +++ b/src/lava/proc/atrlif/process.py @@ -0,0 +1,138 @@ +# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024 Jannik Luboeinski +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +import typing as ty + +from lava.magma.core.process.process import AbstractProcess, LogConfig +from lava.magma.core.process.variable import Var +from lava.magma.core.process.ports.ports import InPort, OutPort + + +class ATRLIF(AbstractProcess): + """ + Adaptive Threshold and Refractoriness Leaky-Integrate-and-Fire Process. + With activation input port `a_in` and spike output port `s_out`. + + Note that non-integer parameter values are supported, but can lead to + deviating results in models that employ fixed-point computation. + + Dynamics (cf. https://github.com/lava-nc/lava-dl/blob/main/src/lava/lib/dl/ + slayer/neuron/alif.py, + https://github.com/lava-nc/lava-dl/blob/main/tutorials/lava/ + lib/dl/slayer/neuron_dynamics/dynamics.ipynb): + i[t] = (1-delta_i)*i[t-1] + x[t] + v[t] = (1-delta_v)*v[t-1] + i[t] + bias + theta[t] = (1-delta_theta)*(theta[t-1] - theta_0) + theta_0 + r[t] = (1-delta_r)*r[t-1] + + Spike event: + s[t] = (v[t] - r[t]) >= theta[t] + + Post spike event: + r[t] = r[t] + 2*theta[t] + theta[t] = theta[t] + theta_step + + Parameters + ---------- + shape : tuple(int) + Number and topology of LIF neurons. + i : float, list, numpy.ndarray, optional + Initial value of the neuron's current. + v : float, list, numpy.ndarray, optional + Initial value of the neuron's voltage (membrane potential). + theta : float, list, numpy.ndarray, optional + Initial value of the threshold + r : float, list, numpy.ndarray, optional + Initial value of the refractory state + s : bool, list, numpy.ndarray, optional + Initial spike state + delta_i : float, optional + Decay constant for current i. + delta_v : float, optional + Decay constant for voltage v. + delta_theta : float, optional + Decay constant for threshold theta. + delta_r : float, optional + Decay constant for refractory state r. + theta_0 : float, optional + Initial/baselien value of threshold theta. + theta_step : float, optional + Increase of threshold theta upon the occurrence of a spike. + bias_mant : float, list, numpy.ndarray, optional + Mantissa part of the neuron's bias. + bias_exp : float, list, numpy.ndarray, optional + Exponent part of the neuron's bias, if needed. Mostly for fixed-point + implementations. Ignored for floating-point implementations. + + Example + ------- + >>> atrlif = ATRLIF(shape=(200, 15), decay_theta=10, decay_v=5) + This will create 200x15 ATRLIF neurons that all have the same threshold + decay of 10 and voltage decay of 5. + """ + + def __init__( + self, + *, + shape: ty.Tuple[int, ...], + i: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + v: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + theta: ty.Optional[ty.Union[float, list, np.ndarray]] = 5, + r: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + s: ty.Optional[ty.Union[bool, list, np.ndarray]] = 0, + delta_i: ty.Optional[float] = 0.4, + delta_v: ty.Optional[float] = 0.4, + delta_theta: ty.Optional[float] = 0.2, + delta_r: ty.Optional[float] = 0.2, + theta_0: ty.Optional[float] = 5, + theta_step: ty.Optional[float] = 3.75, + bias_mant: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + bias_exp: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + name: ty.Optional[str] = None, + log_config: ty.Optional[LogConfig] = None + ) -> None: + + super().__init__( + shape=shape, + i=i, + v=v, + theta=theta, + r=r, + s=s, + delta_i=delta_i, + delta_v=delta_v, + delta_theta=delta_theta, + delta_r=delta_r, + theta_0=theta_0, + theta_step=theta_step, + bias_mant=bias_mant, + bias_exp=bias_exp, + name=name, + log_config=log_config + ) + + # Ports + self.a_in = InPort(shape=shape) + self.s_out = OutPort(shape=shape) + + # Bias + self.bias_mant = Var(shape=shape, init=bias_mant) + self.bias_exp = Var(shape=shape, init=bias_exp) + + # Variables + self.i = Var(shape=shape, init=i) + self.v = Var(shape=shape, init=v) + self.theta = Var(shape=shape, init=theta) + self.r = Var(shape=shape, init=r) + self.s = Var(shape=shape, init=s) + + # Parameters + self.delta_i = Var(shape=(1,), init=delta_i) + self.delta_v = Var(shape=(1,), init=delta_v) + self.delta_theta = Var(shape=(1,), init=delta_theta) + self.delta_r = Var(shape=(1,), init=delta_r) + self.theta_0 = Var(shape=(1,), init=theta_0) + self.theta_step = Var(shape=(1,), init=theta_step) diff --git a/src/lava/proc/clp/id_broadcast/models.py b/src/lava/proc/clp/id_broadcast/models.py new file mode 100644 index 000000000..96b7f283b --- /dev/null +++ b/src/lava/proc/clp/id_broadcast/models.py @@ -0,0 +1,32 @@ +# Copyright (C) 2022 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +from lava.magma.core.decorator import implements, requires +from lava.magma.core.model.py.model import PyLoihiProcessModel +from lava.magma.core.model.py.ports import PyInPort, PyOutPort +from lava.magma.core.model.py.type import LavaPyType +from lava.magma.core.resources import CPU +from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol + +from lava.proc.clp.id_broadcast.process import IdBroadcast + + +@implements(proc=IdBroadcast, protocol=LoihiProtocol) +@requires(CPU) +class IdBroadcastModel(PyLoihiProcessModel): + """CPU model for the IdBroadcast process. + + The process sends out a graded spike with payload equal to a_in. + """ + a_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, int) + s_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, int) + val: np.ndarray = LavaPyType(np.ndarray, np.int32) + + def run_spk(self): + """Execute spiking phase, send value of a_in.""" + + a_in_data = self.a_in.recv() + self.val = a_in_data + self.s_out.send(a_in_data) diff --git a/src/lava/proc/clp/id_broadcast/process.py b/src/lava/proc/clp/id_broadcast/process.py new file mode 100644 index 000000000..6e4e27c85 --- /dev/null +++ b/src/lava/proc/clp/id_broadcast/process.py @@ -0,0 +1,34 @@ +# Copyright (C) 2022 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import typing as ty + +from lava.magma.core.process.ports.ports import InPort, OutPort +from lava.magma.core.process.variable import Var +from lava.magma.core.process.process import AbstractProcess, LogConfig + + +class IdBroadcast(AbstractProcess): + """Process that sends out a graded spike with payload equal to a_in. + + Parameters + ---------- + shape : tuple(int) + Shape of the population of process units. + name : str + Name of the Process. Default is 'Process_ID', where ID is an + integer value that is determined automatically. + log_config : LogConfig + Configuration options for logging. + """ + + def __init__(self, *, + shape: ty.Tuple[int, ...] = (1,), + name: ty.Optional[str] = None, + log_config: ty.Optional[LogConfig] = None) -> None: + super().__init__(shape=shape, name=name, log_config=log_config) + self.a_in = InPort(shape=shape) + self.s_out = OutPort(shape=shape) + + self.val = Var(shape=shape, init=0) diff --git a/src/lava/proc/conv_in_time/models.py b/src/lava/proc/conv_in_time/models.py new file mode 100644 index 000000000..68b603d4a --- /dev/null +++ b/src/lava/proc/conv_in_time/models.py @@ -0,0 +1,99 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np + +from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol +from lava.magma.core.model.py.ports import PyInPort, PyOutPort +from lava.magma.core.model.py.type import LavaPyType +from lava.magma.core.resources import CPU +from lava.magma.core.decorator import implements, requires, tag +from lava.magma.core.model.py.model import PyLoihiProcessModel +from lava.proc.conv_in_time.process import ConvInTime +from lava.proc.conv import utils + + +class AbstractPyConvInTimeModel(PyLoihiProcessModel): + """Abstract Conn In Time Process with Dense synaptic connections + which incorporates delays into the Conv Process. + """ + weights: np.ndarray = None + a_buff: np.ndarray = None + kernel_size: int = None + + num_message_bits: np.ndarray = LavaPyType(np.ndarray, np.int8, precision=5) + + def calc_act(self, s_in) -> np.ndarray: + """ + Calculate the activation buff by inverse the order in + the kernel. Taking k=3 as an example, the a_buff will be + weights[2] * s_in, weights[1] * s_in, weights[0] * s_in + """ + + # The change of the shape is shown below: + # sum([K, n_out, n_in] * [n_in,], axis=-1) = [K, n_out] -> [n_out, K] + kernel_size = self.weights.shape[0] + for i in range(kernel_size): + self.a_buff[:, i] += np.sum( + self.weights[kernel_size - i - 1] * s_in, axis=-1).T + + def update_act(self, s_in): + """ + Updates the activations for the connection. + Clears first column of a_buff and rolls them to the last column. + Finally, calculates the activations for the current time step and adds + them to a_buff. + This order of operations ensures that delays of 0 correspond to + the next time step. + """ + self.a_buff[:, 0] = 0 + self.a_buff = np.roll(self.a_buff, -1) + self.calc_act(s_in) + + def run_spk(self): + # The a_out sent on a each timestep is a buffered value from dendritic + # accumulation at timestep t-1. This prevents deadlocking in + # networks with recurrent connectivity structures. + self.a_out.send(self.a_buff[:, 0]) + if self.num_message_bits.item() > 0: + s_in = self.s_in.recv() + else: + s_in = self.s_in.recv().astype(bool) + self.update_act(s_in) + + +@implements(proc=ConvInTime, protocol=LoihiProtocol) +@requires(CPU) +@tag("floating_pt") +class PyConvInTimeFloat(AbstractPyConvInTimeModel): + """Implementation of Conn In Time Process with Dense synaptic connections in + floating point precision. This short and simple ProcessModel can be used + for quick algorithmic prototyping, without engaging with the nuances of a + fixed point implementation. DelayDense incorporates delays into the Conn + Process. + """ + s_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, bool, precision=1) + a_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) + a_buff: np.ndarray = LavaPyType(np.ndarray, float) + # The weights is a 3D matrix of form (kernel_size, + # num_flat_output_neurons, num_flat_input_neurons) in C-order (row major). + weights: np.ndarray = LavaPyType(np.ndarray, float) + num_message_bits: np.ndarray = LavaPyType(np.ndarray, int, precision=5) + + +@implements(proc=ConvInTime, protocol=LoihiProtocol) +@requires(CPU) +@tag("fixed_pt") +class PyConvInTimeFixed(AbstractPyConvInTimeModel): + """Conv In Time with fixed point synapse implementation.""" + s_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, bool, precision=1) + a_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) + a_buff: np.ndarray = LavaPyType(np.ndarray, float) + # The weights is a 3D matrix of form (kernel_size, + # num_flat_output_neurons, num_flat_input_neurons) in C-order (row major). + weights: np.ndarray = LavaPyType(np.ndarray, float) + num_message_bits: np.ndarray = LavaPyType(np.ndarray, int, precision=5) + + def clamp_precision(self, x: np.ndarray) -> np.ndarray: + return utils.signed_clamp(x, bits=24) diff --git a/src/lava/proc/conv_in_time/process.py b/src/lava/proc/conv_in_time/process.py new file mode 100644 index 000000000..ec54d657f --- /dev/null +++ b/src/lava/proc/conv_in_time/process.py @@ -0,0 +1,86 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +import typing as ty + +from lava.magma.core.process.process import AbstractProcess, LogConfig +from lava.magma.core.process.variable import Var +from lava.magma.core.process.ports.ports import InPort, OutPort + + +class ConvInTime(AbstractProcess): + """Connection Process that mimics a convolution of the incoming + events/spikes with a kernel in the time dimension. Realizes the + following abstract behavior: a_out[t] = weights[t-1] * s_in[t-1] + + weights[t] * s_in[t] + weights[t+1] * s_in[t+1] + + Parameters + ---------- + weights : numpy.ndarray + 3D connection weight matrix of form (kernel_size, + num_flat_output_neurons, num_flat_input_neurons) + in C-order (row major). + + weight_exp : int, optional + Shared weight exponent of base 2 used to scale magnitude of + weights, if needed. Mostly for fixed point implementations. + Unnecessary for floating point implementations. + Default value is 0. + + num_weight_bits : int, optional + Shared weight width/precision used by weight. Mostly for fixed + point implementations. Unnecessary for floating point + implementations. + Default is for weights to use full 8 bit precision. + + sign_mode : SignMode, optional + Shared indicator whether synapse is of type SignMode.NULL, + SignMode.MIXED, SignMode.EXCITATORY, or SignMode.INHIBITORY. If + SignMode.MIXED, the sign of the weight is + included in the weight bits and the fixed point weight used for + inference is scaled by 2. + Unnecessary for floating point implementations. + + In the fixed point implementation, weights are scaled according to + the following equations: + w_scale = 8 - num_weight_bits + weight_exp + isMixed() + weights = weights * (2 ** w_scale) + + num_message_bits : int, optional + Determines whether the Dense Process deals with the incoming + spikes as binary spikes (num_message_bits = 0) or as graded + spikes (num_message_bits > 0). Default is 0. + """ + def __init__(self, + *, + weights: np.ndarray, + name: ty.Optional[str] = None, + num_message_bits: ty.Optional[int] = 0, + log_config: ty.Optional[LogConfig] = None, + **kwargs) -> None: + + super().__init__(weights=weights, + num_message_bits=num_message_bits, + name=name, + log_config=log_config, + **kwargs) + + self._validate_weights(weights) + # [kernel_size, n_flat_output_neurons, n_flat_input_neurons] + shape = weights.shape + # Ports + self.s_in = InPort(shape=(shape[2],)) + self.a_out = OutPort(shape=(shape[1],)) + + # Variables + self.weights = Var(shape=shape, init=weights) + self.a_buff = Var(shape=(shape[1], shape[0]), init=0) + self.num_message_bits = Var(shape=(1,), init=num_message_bits) + + @staticmethod + def _validate_weights(weights: np.ndarray) -> None: + if len(np.shape(weights)) != 3: + raise ValueError("Dense Process 'weights' expects a 3D matrix, " + f"got {weights}.") diff --git a/src/lava/proc/dense/process.py b/src/lava/proc/dense/process.py index c2c0baf7e..9a82fc5ee 100644 --- a/src/lava/proc/dense/process.py +++ b/src/lava/proc/dense/process.py @@ -152,6 +152,8 @@ class LearningDense(LearningConnectionProcess, Dense): def __init__(self, *, weights: np.ndarray, + tag_2: ty.Optional[np.ndarray] = None, + tag_1: ty.Optional[np.ndarray] = None, name: ty.Optional[str] = None, num_message_bits: ty.Optional[int] = 0, log_config: ty.Optional[LogConfig] = None, @@ -164,6 +166,8 @@ def __init__(self, learning_rule.x1_impulse = 0 super().__init__(weights=weights, + tag_2=tag_2, + tag_1=tag_1, shape=weights.shape, name=name, num_message_bits=num_message_bits, @@ -172,6 +176,15 @@ def __init__(self, graded_spike_cfg=graded_spike_cfg, **kwargs) + if tag_2 is None: + tag_2 = np.zeros(weights.shape) + + if tag_1 is None: + tag_1 = np.zeros(weights.shape) + + self.tag_2.init = tag_2.copy() + self.tag_1.init = tag_1.copy() + class DelayDense(Dense): def __init__(self, diff --git a/src/lava/proc/graded/models.py b/src/lava/proc/graded/models.py index b87f925a9..870b0b301 100644 --- a/src/lava/proc/graded/models.py +++ b/src/lava/proc/graded/models.py @@ -11,7 +11,8 @@ from lava.magma.core.decorator import implements, requires, tag from lava.magma.core.model.py.model import PyLoihiProcessModel -from lava.proc.graded.process import GradedVec, NormVecDelay, InvSqrt +from lava.proc.graded.process import (GradedVec, GradedReluVec, + NormVecDelay, InvSqrt) class AbstractGradedVecModel(PyLoihiProcessModel): @@ -51,6 +52,43 @@ class PyGradedVecModelFixed(AbstractGradedVecModel): exp: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=24) +class AbstractGradedReluVecModel(PyLoihiProcessModel): + """Implementation of GradedReluVec""" + + a_in = None + s_out = None + v = None + vth = None + exp = None + + def run_spk(self) -> None: + """The run function that performs the actual computation during + execution orchestrated by a PyLoihiProcessModel using the + LoihiProtocol. + """ + a_in_data = self.a_in.recv() + self.v += a_in_data + + is_spike = self.v > self.vth + sp_out = self.v * is_spike + + self.v[:] = 0 + + self.s_out.send(sp_out) + + +@implements(proc=GradedReluVec, protocol=LoihiProtocol) +@requires(CPU) +@tag('fixed_pt') +class PyGradedReluVecModelFixed(AbstractGradedReluVecModel): + """Fixed point implementation of GradedVec""" + a_in = LavaPyType(PyInPort.VEC_DENSE, np.int32, precision=24) + s_out = LavaPyType(PyOutPort.VEC_DENSE, np.int32, precision=24) + vth: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=24) + v: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=24) + exp: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=24) + + @implements(proc=NormVecDelay, protocol=LoihiProtocol) @requires(CPU) @tag('fixed_pt') @@ -92,7 +130,7 @@ def run_spk(self) -> None: @implements(proc=InvSqrt, protocol=LoihiProtocol) @requires(CPU) -@tag('float') +@tag('floating_pt') class InvSqrtModelFloat(PyLoihiProcessModel): """Implementation of InvSqrt in floating point""" a_in = LavaPyType(PyInPort.VEC_DENSE, float) @@ -111,9 +149,19 @@ def run_spk(self) -> None: self.s_out.send(sp_out) -def make_fpinv_table(fp_base): +def make_fpinv_table(fp_base: int) -> np.ndarray: """ - Creates the table for fp inverse algorithm. + Creates the table for fp inverse square root algorithm. + + Parameters + ---------- + fp_base : int + Base of the fixed point. + + Returns + ------- + Y_est : np.ndarray + Initialization look-up table for fp inverse square root. """ n_bits = 24 B = 2**fp_base @@ -121,22 +169,49 @@ def make_fpinv_table(fp_base): Y_est = np.zeros((n_bits), dtype='int') n_adj = 1.238982962 - for m in range(n_bits): # span the 24 bits, negate the decimal base + for m in range(n_bits): # Span the 24 bits, negate the decimal base Y_est[n_bits - m - 1] = 2 * int(B / (2**((m - fp_base) / 2) * n_adj)) return Y_est -def clz(val): +def clz(val: int) -> int: """ Count lead zeros. + + Parameters + ---------- + val : int + Integer value for counting lead zeros. + + Returns + ------- + out_val : int + Number of leading zeros. """ - return (24 - (int(np.log2(val)) + 1)) + out_val = (24 - (int(np.log2(val)) + 1)) + return out_val -def inv_sqrt(s_fp, n_iters=5, b_fraction=12): +def inv_sqrt(s_fp: int, + n_iters: int = 5, + b_fraction: int = 12) -> int: """ - Runs the fixed point inverse square root algorithm + Runs the fixed point inverse square root algorithm. + + Parameters + ---------- + s_fp : int + Fixed point value to calulate inverse square root. + n_iters : int, optional + Number of iterations for fixed point inverse square root algorithm. + b_fraction : int, optional + Fixed point base. + + Returns + ------- + y_i : int + Approximate inverse square root in fixed point. """ Y_est = make_fpinv_table(b_fraction) m = clz(s_fp) diff --git a/src/lava/proc/graded/process.py b/src/lava/proc/graded/process.py index 6c5943a46..25c881b50 100644 --- a/src/lava/proc/graded/process.py +++ b/src/lava/proc/graded/process.py @@ -10,12 +10,23 @@ from lava.magma.core.process.ports.ports import InPort, OutPort -def loihi2round(vv): +def loihi2round(vv: np.ndarray) -> np.ndarray: """ Round values in numpy array the way loihi 2 performs rounding/truncation. + + Parameters + ---------- + vv : np.ndarray + Input values to be rounded consistent with loihi2 rouding. + + Returns + ------- + vv_r : np.ndarray + Output values rounded consistent with loihi2 rouding. """ - return np.fix(vv + (vv > 0) - 0.5).astype('int') + vv_r = np.fix(vv + (vv > 0) - 0.5).astype('int') + return vv_r class GradedVec(AbstractProcess): @@ -24,7 +35,7 @@ class GradedVec(AbstractProcess): graded spike with no dynamics. v[t] = a_in - s_out = v[t] * (v[t] > vth) + s_out = v[t] * (|v[t]| > vth) Parameters ---------- @@ -57,6 +68,45 @@ def shape(self) -> ty.Tuple[int, ...]: return self.proc_params['shape'] +class GradedReluVec(AbstractProcess): + """GradedReluVec + Graded spike vector layer. Transmits accumulated input as + graded spike with no dynamics. + + v[t] = a_in + s_out = v[t] * (v[t] > vth) + + Parameters + ---------- + shape : tuple(int) + Number and topology of neurons. + vth : int + Threshold for spiking. + exp : int + Fixed point base. + """ + + def __init__( + self, + shape: ty.Tuple[int, ...], + vth: ty.Optional[int] = 1, + exp: ty.Optional[int] = 0) -> None: + + super().__init__(shape=shape) + + self.a_in = InPort(shape=shape) + self.s_out = OutPort(shape=shape) + + self.v = Var(shape=shape, init=0) + self.vth = Var(shape=(1,), init=vth) + self.exp = Var(shape=(1,), init=exp) + + @property + def shape(self) -> ty.Tuple[int, ...]: + """Return shape of the Process.""" + return self.proc_params['shape'] + + class NormVecDelay(AbstractProcess): """NormVec Normalizable graded spike vector. Used in conjunction with @@ -78,12 +128,12 @@ class NormVecDelay(AbstractProcess): Parameters ---------- - shape: tuple(int) - number and topology of neurons - vth: int - threshold for spiking - exp: int - fixed point base + shape : tuple(int) + Number and topology of neurons. + vth : int + Threshold for spiking. + exp : int + Fixed point base. """ def __init__( @@ -123,8 +173,11 @@ class InvSqrt(AbstractProcess): Parameters ---------- + shape : tuple(int) + Number and topology of neurons. + fp_base : int - Base of the fixed-point representation + Base of the fixed-point representation. """ def __init__( @@ -133,7 +186,7 @@ def __init__( fp_base: ty.Optional[int] = 12) -> None: super().__init__(shape=shape) - # base of the decimal point + # Base of the decimal point self.fp_base = Var(shape=(1,), init=fp_base) self.a_in = InPort(shape=shape) self.s_out = OutPort(shape=shape) diff --git a/src/lava/proc/io/extractor.py b/src/lava/proc/io/extractor.py index 1f0ca1cf8..48ea87de6 100644 --- a/src/lava/proc/io/extractor.py +++ b/src/lava/proc/io/extractor.py @@ -6,13 +6,15 @@ import typing as ty from lava.magma.core.process.process import AbstractProcess -from lava.magma.core.process.ports.ports import InPort, RefPort, Var +from lava.magma.core.process.ports.ports import InPort, OutPort, RefPort, Var from lava.magma.core.resources import CPU from lava.magma.core.decorator import implements, requires from lava.magma.core.model.py.model import PyLoihiProcessModel +from lava.magma.core.model.py.model import PyAsyncProcessModel from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol +from lava.magma.core.sync.protocols.async_protocol import AsyncProtocol from lava.magma.core.model.py.type import LavaPyType -from lava.magma.core.model.py.ports import PyInPort, PyRefPort +from lava.magma.core.model.py.ports import PyInPort, PyOutPort, PyRefPort from lava.magma.compiler.channels.pypychannel import PyPyChannel from lava.magma.runtime.message_infrastructure.multiprocessing import \ MultiProcessing @@ -51,9 +53,9 @@ class Extractor(AbstractProcess): def __init__(self, shape: ty.Tuple[int, ...], buffer_size: ty.Optional[int] = 50, - channel_config: ty.Optional[utils.ChannelConfig] = None) -> \ - None: - super().__init__() + channel_config: ty.Optional[utils.ChannelConfig] = None, + **kwargs) -> None: + super().__init__(shape_1=shape, **kwargs) channel_config = channel_config or utils.ChannelConfig() @@ -63,78 +65,86 @@ def __init__(self, self._shape = shape - self._multi_processing = MultiProcessing() - self._multi_processing.start() - - # Stands for ProcessModel to Process - pm_to_p = PyPyChannel(message_infrastructure=self._multi_processing, - src_name="src", - dst_name="dst", - shape=self._shape, - dtype=float, - size=buffer_size) - self._pm_to_p_dst_port = pm_to_p.dst_port - self._pm_to_p_dst_port.start() - self.proc_params["channel_config"] = channel_config - self.proc_params["pm_to_p_src_port"] = pm_to_p.src_port self._receive_when_empty = channel_config.get_receive_empty_function() self._receive_when_not_empty = \ channel_config.get_receive_not_empty_function() - self.in_port = InPort(shape=self._shape) + self.in_port = InPort(shape=shape) + self.out_port = OutPort(shape=shape) + self.out_port.flag_external_pipe(buffer_size=buffer_size) def receive(self) -> np.ndarray: """Receive data from the ProcessModel. - The data is received from pm_to_p.dst_port. + The data is received from out_port. Returns ---------- data : np.ndarray Data received. """ - elements_in_buffer = self._pm_to_p_dst_port._queue.qsize() + if not hasattr(self.out_port, 'external_pipe_csp_recv_port'): + raise AssertionError("The Runtime needs to be created before" + "calling . Please use the method " + " or on your Lava" + " network before using .") + + elements_in_buffer = \ + self.out_port.external_pipe_csp_recv_port._queue.qsize() if elements_in_buffer == 0: data = self._receive_when_empty( - self._pm_to_p_dst_port, + self.out_port.external_pipe_csp_recv_port, np.zeros(self._shape)) else: data = self._receive_when_not_empty( - self._pm_to_p_dst_port, + self.out_port.external_pipe_csp_recv_port, np.zeros(self._shape), elements_in_buffer) return data - def __del__(self) -> None: - super().__del__() - - self._multi_processing.stop() - self._pm_to_p_dst_port.join() - @implements(proc=Extractor, protocol=LoihiProtocol) @requires(CPU) class PyLoihiExtractorModel(PyLoihiProcessModel): + """PyLoihiProcessModel for the Extractor Process.""" in_port: PyInPort = LavaPyType(PyInPort.VEC_DENSE, float) + out_port: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) def __init__(self, proc_params: dict) -> None: super().__init__(proc_params=proc_params) channel_config = self.proc_params["channel_config"] - self._pm_to_p_src_port = self.proc_params["pm_to_p_src_port"] - self._pm_to_p_src_port.start() self._send = channel_config.get_send_full_function() def run_spk(self) -> None: - self._send(self._pm_to_p_src_port, self.in_port.recv()) + self._send(self.out_port.csp_ports[-1], + self.in_port.recv()) - def __del__(self) -> None: - self._pm_to_p_src_port.join() + +@implements(proc=Extractor, protocol=AsyncProtocol) +@requires(CPU) +class PyLoihiExtractorModelAsync(PyAsyncProcessModel): + in_port: PyInPort = LavaPyType(PyInPort.VEC_DENSE, float) + out_port: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) + + def __init__(self, proc_params: dict) -> None: + super().__init__(proc_params=proc_params) + + channel_config = self.proc_params["channel_config"] + + self._send = channel_config.get_send_full_function() + self.time_step = 1 + + def run_async(self) -> None: + while self.time_step != self.num_steps + 1: + self._send(self.out_port.csp_ports[-1], + self.in_port.recv()) + self.time_step += 1 class VarWire(AbstractProcess): diff --git a/src/lava/proc/io/injector.py b/src/lava/proc/io/injector.py index e0c4207e5..65ad0c8d0 100644 --- a/src/lava/proc/io/injector.py +++ b/src/lava/proc/io/injector.py @@ -6,16 +6,15 @@ import typing as ty from lava.magma.core.process.process import AbstractProcess -from lava.magma.core.process.ports.ports import OutPort +from lava.magma.core.process.ports.ports import InPort, OutPort from lava.magma.core.resources import CPU from lava.magma.core.decorator import implements, requires from lava.magma.core.model.py.model import PyLoihiProcessModel +from lava.magma.core.model.py.model import PyAsyncProcessModel from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol +from lava.magma.core.sync.protocols.async_protocol import AsyncProtocol from lava.magma.core.model.py.type import LavaPyType -from lava.magma.core.model.py.ports import PyOutPort -from lava.magma.runtime.message_infrastructure.multiprocessing import \ - MultiProcessing -from lava.magma.compiler.channels.pypychannel import PyPyChannel +from lava.magma.core.model.py.ports import PyInPort, PyOutPort from lava.proc.io import utils @@ -51,9 +50,9 @@ class Injector(AbstractProcess): def __init__(self, shape: ty.Tuple[int, ...], buffer_size: ty.Optional[int] = 50, - channel_config: ty.Optional[utils.ChannelConfig] = None) -> \ - None: - super().__init__() + channel_config: ty.Optional[utils.ChannelConfig] = None, + **kwargs) -> None: + super().__init__(shape_1=shape, **kwargs) channel_config = channel_config or utils.ChannelConfig() @@ -61,50 +60,43 @@ def __init__(self, utils.validate_buffer_size(buffer_size) utils.validate_channel_config(channel_config) - self._multi_processing = MultiProcessing() - self._multi_processing.start() - - # Stands for Process to ProcessModel - p_to_pm = PyPyChannel(message_infrastructure=self._multi_processing, - src_name="src", - dst_name="dst", - shape=shape, - dtype=float, - size=buffer_size) - self._p_to_pm_src_port = p_to_pm.src_port - self._p_to_pm_src_port.start() + self.in_port = InPort(shape=shape) + self.in_port.flag_external_pipe(buffer_size=buffer_size) + self.out_port = OutPort(shape=shape) self.proc_params["shape"] = shape self.proc_params["channel_config"] = channel_config - self.proc_params["p_to_pm_dst_port"] = p_to_pm.dst_port self._send = channel_config.get_send_full_function() - self.out_port = OutPort(shape=shape) - def send(self, data: np.ndarray) -> None: - """Send data to the ProcessModel. - - The data is sent through p_to_pm.src_port. + """Send data to connected process. Parameters ---------- data : np.ndarray Data to be sent. - """ - self._send(self._p_to_pm_src_port, data) - - def __del__(self) -> None: - super().__del__() - self._multi_processing.stop() - self._p_to_pm_src_port.join() + Raises + ------ + AssertionError + If the runtime of the Lava network was not created. + """ + # The csp channel is created by the runtime + if hasattr(self.in_port, 'external_pipe_csp_send_port'): + self._send(self.in_port.external_pipe_csp_send_port, data) + else: + raise AssertionError("The Runtime needs to be created before" + "calling . Please use the method " + " or on your Lava" + " network before using .") @implements(proc=Injector, protocol=LoihiProtocol) @requires(CPU) class PyLoihiInjectorModel(PyLoihiProcessModel): """PyLoihiProcessModel for the Injector Process.""" + in_port: PyInPort = LavaPyType(PyInPort.VEC_DENSE, float) out_port: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) def __init__(self, proc_params: dict) -> None: @@ -112,9 +104,6 @@ def __init__(self, proc_params: dict) -> None: shape = self.proc_params["shape"] channel_config = self.proc_params["channel_config"] - self._p_to_pm_dst_port = self.proc_params["p_to_pm_dst_port"] - self._p_to_pm_dst_port.start() - self._zeros = np.zeros(shape) self._receive_when_empty = channel_config.get_receive_empty_function() @@ -123,15 +112,15 @@ def __init__(self, proc_params: dict) -> None: def run_spk(self) -> None: self._zeros.fill(0) - elements_in_buffer = self._p_to_pm_dst_port._queue.qsize() + elements_in_buffer = self.in_port.csp_ports[-1]._queue.qsize() if elements_in_buffer == 0: data = self._receive_when_empty( - self._p_to_pm_dst_port, + self.in_port, self._zeros) else: data = self._receive_when_not_empty( - self._p_to_pm_dst_port, + self.in_port, self._zeros, elements_in_buffer) @@ -139,3 +128,44 @@ def run_spk(self) -> None: def __del__(self) -> None: self._p_to_pm_dst_port.join() + + +@implements(proc=Injector, protocol=AsyncProtocol) +@requires(CPU) +class PyLoihiInjectorModelAsync(PyAsyncProcessModel): + """PyAsyncProcessModel for the Injector Process.""" + in_port: PyInPort = LavaPyType(PyInPort.VEC_DENSE, float) + out_port: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) + + def __init__(self, proc_params: dict) -> None: + super().__init__(proc_params=proc_params) + + shape = self.proc_params["shape"] + channel_config = self.proc_params["channel_config"] + self._zeros = np.zeros(shape) + + self._receive_when_empty = channel_config.get_receive_empty_function() + self._receive_when_not_empty = \ + channel_config.get_receive_not_empty_function() + self.time_step = 1 + + def run_async(self) -> None: + while self.time_step != self.num_steps + 1: + self._zeros.fill(0) + elements_in_buffer = self.in_port.csp_ports[-1]._queue.qsize() + + if elements_in_buffer == 0: + data = self._receive_when_empty( + self.in_port, + self._zeros) + else: + data = self._receive_when_not_empty( + self.in_port, + self._zeros, + elements_in_buffer) + + self.out_port.send(data) + self.time_step += 1 + + def __del__(self) -> None: + self._p_to_pm_dst_port.join() diff --git a/src/lava/proc/lif/models.py b/src/lava/proc/lif/models.py index b58ffe7db..72f02be9b 100644 --- a/src/lava/proc/lif/models.py +++ b/src/lava/proc/lif/models.py @@ -477,9 +477,8 @@ def subthr_dynamics(self, activation_in: np.ndarray): self.u[:] = self.u * (1 - self.du) self.u[:] += activation_in non_refractory = self.refractory_period_end < self.time_step - self.v[non_refractory] = (self.v[non_refractory] * ( - (1 - self.dv) + self.u[non_refractory]) - + self.bias_mant[non_refractory]) + self.v[non_refractory] = self.v[non_refractory] * (1 - self.dv) + ( + self.u[non_refractory] + self.bias_mant[non_refractory]) def process_spikes(self, spike_vector: np.ndarray): self.refractory_period_end[spike_vector] = (self.time_step diff --git a/src/lava/proc/prodneuron/process.py b/src/lava/proc/prodneuron/process.py index 417ed5490..94d1a10c9 100644 --- a/src/lava/proc/prodneuron/process.py +++ b/src/lava/proc/prodneuron/process.py @@ -20,7 +20,7 @@ def __init__( Multiplies two graded inputs and outputs result as graded spike. v[t] = (a_in1 * a_in2) >> exp - s_out = v[t] * (v[t] > vth) + s_out = v[t] * (|v[t]| > vth) Parameters ---------- diff --git a/src/lava/proc/receiver/process.py b/src/lava/proc/receiver/process.py index 52e2679a4..d49b4e92f 100644 --- a/src/lava/proc/receiver/process.py +++ b/src/lava/proc/receiver/process.py @@ -1,4 +1,4 @@ -# Copyright (C) 2022 Intel Corporation +# Copyright (C) 2022-2023 Intel Corporation # SPDX-License-Identifier: BSD-3-Clause # See: https://spdx.org/licenses/ @@ -30,3 +30,30 @@ def __init__(self, *, super().__init__(shape=shape, name=name, log_config=log_config) self.a_in = InPort(shape=shape) self.payload = Var(shape=shape, init=0) + + +class Receiver32Bit(AbstractProcess): + """Process saving input messages as a payload variable. For up to 32bit + payload. + + Parameters + ---------- + shape : tuple(int) + Shape of the population of process units. + name : str + Name of the Process. Default is 'Process_ID', where ID is an + integer value that is determined automatically. + log_config : LogConfig + Configuration options for logging. + """ + + def __init__(self, *, + shape: ty.Tuple[int, ...] = (1,), + name: ty.Optional[str] = None, + log_config: ty.Optional[LogConfig] = None) -> None: + super().__init__(shape=shape, name=name, log_config=log_config) + self.a_in = InPort(shape=shape) + + # Total payload = (payload_first_byte << 24) + payload_last_bytes + self.payload_last_bytes = Var(shape=shape, init=0) + self.payload_first_byte = Var(shape=shape, init=0) diff --git a/src/lava/proc/s4d/models.py b/src/lava/proc/s4d/models.py new file mode 100644 index 000000000..520f445f1 --- /dev/null +++ b/src/lava/proc/s4d/models.py @@ -0,0 +1,234 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +from typing import Any, Dict +from lava.proc.sdn.models import AbstractSigmaDeltaModel +from lava.magma.core.decorator import implements, requires, tag +from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol +from lava.proc.s4d.process import SigmaS4dDelta, SigmaS4dDeltaLayer, S4d +from lava.magma.core.resources import CPU +from lava.magma.core.model.py.ports import PyInPort, PyOutPort +from lava.magma.core.model.py.type import LavaPyType +from lava.magma.core.model.sub.model import AbstractSubProcessModel +from lava.proc.sparse.process import Sparse +from lava.magma.core.model.py.model import PyLoihiProcessModel + + +@implements(proc=S4d, protocol=LoihiProtocol) +@requires(CPU) +@tag('floating_pt') +class S4dModel(PyLoihiProcessModel): + a_in = LavaPyType(PyInPort.VEC_DENSE, float) + s_out = LavaPyType(PyOutPort.VEC_DENSE, float) + s4_exp: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=3) + inp_exp: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=3) + + # S4 variables + s4_state: np.ndarray = LavaPyType(np.ndarray, complex) + a: np.ndarray = LavaPyType(np.ndarray, complex) + b: np.ndarray = LavaPyType(np.ndarray, complex) + c: np.ndarray = LavaPyType(np.ndarray, complex) + + def __init__(self, proc_params: Dict[str, Any]) -> None: + """ + Neuron model that implements S4D + (as described by Gu et al., 2022) dynamics. + + Relevant parameters in proc_params + -------------------------- + a: np.ndarray + Diagonal elements of the state matrix of the discretized S4D model. + b: np.ndarray + Diagonal elements of the input matrix of the discretized S4D model. + c: np.ndarray + Diagonal elements of the output matrix of the discretized S4D model. + s4_state: np.ndarray + State vector of the S4D discretized model. + """ + super().__init__(proc_params) + self.a = self.proc_params['a'] + self.b = self.proc_params['b'] + self.c = self.proc_params['c'] + self.s4_state = self.proc_params['s4_state'] + + def run_spk(self) -> None: + """Performs S4D dynamics. + + This function simulates the behavior of a linear time-invariant system + with diagonalized state-space representation. + (For reference see Gu et al., 2022) + + The state-space equations are given by: + s4_state_{k+1} = A * s4_state_k + B * input_k + act_k = C * s4_state_k + + where: + - s4_state_k is the state vector at time step k, + - input_k is the input vector at time step k, + - act_k is the output vector at time step k, + - A is the diagonal state matrix, + - B is the diagonal input matrix, + - C is the diagonal output matrix. + + The function computes the next output step of the + system for the given input signal. + """ + inp = self.a_in.recv() + self.s4_state = (self.s4_state * self.a + inp * self.b) + self.s_out.send(np.real(self.c * self.s4_state * 2)) + + +class AbstractSigmaS4dDeltaModel(AbstractSigmaDeltaModel): + a_in = None + s_out = None + + # SigmaDelta Variables + vth = None + sigma = None + act = None + residue = None + error = None + state_exp = None + bias = None + + # S4 Variables + a = None + b = None + c = None + s4_state = None + s4_exp = None + + def __init__(self, proc_params: Dict[str, Any]) -> None: + """ + Sigma delta neuron model that implements S4D + (as described by Gu et al., 2022) dynamics as its activation function. + + Relevant parameters in proc_params + -------------------------- + a: np.ndarray + Diagonal elements of the state matrix of the S4D model. + b: np.ndarray + Diagonal elements of the input matrix of the S4D model. + c: np.ndarray + Diagonal elements of the output matrix of the S4D model. + s4_state: np.ndarray + State vector of the S4D model. + """ + super().__init__(proc_params) + self.a = self.proc_params['a'] + self.b = self.proc_params['b'] + self.c = self.proc_params['c'] + self.s4_state = self.proc_params['s4_state'] + + def activation_dynamics(self, sigma_data: np.ndarray) -> np.ndarray: + """Sigma Delta activation dynamics. Performs S4D dynamics. + + This function simulates the behavior of a linear time-invariant system + with diagonalized state-space representation. + (For reference see Gu et al., 2022) + + The state-space equations are given by: + s4_state_{k+1} = A * s4_state_k + B * input_k + act_k = C * s4_state_k + + where: + - s4_state_k is the state vector at time step k, + - input_k is the input vector at time step k, + - act_k is the output vector at time step k, + - A is the diagonal state matrix, + - B is the diagonal input matrix, + - C is the diagonal output matrix. + + The function computes the next output step of the + system for the given input signal. + + Parameters + ---------- + sigma_data: np.ndarray + sigma decoded data + + Returns + ------- + np.ndarray + activation output + """ + + self.s4_state = self.s4_state * self.a + sigma_data * self.b + act = self.c * self.s4_state * 2 + return act + + +@implements(proc=SigmaS4dDelta, protocol=LoihiProtocol) +@requires(CPU) +@tag('floating_pt') +class PySigmaS4dDeltaModelFloat(AbstractSigmaS4dDeltaModel): + """Floating point implementation of SigmaS4dDelta neuron.""" + a_in = LavaPyType(PyInPort.VEC_DENSE, float) + s_out = LavaPyType(PyOutPort.VEC_DENSE, float) + + vth: np.ndarray = LavaPyType(np.ndarray, float) + sigma: np.ndarray = LavaPyType(np.ndarray, float) + act: np.ndarray = LavaPyType(np.ndarray, float) + residue: np.ndarray = LavaPyType(np.ndarray, float) + error: np.ndarray = LavaPyType(np.ndarray, float) + bias: np.ndarray = LavaPyType(np.ndarray, float) + + state_exp: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=3) + cum_error: np.ndarray = LavaPyType(np.ndarray, bool, precision=1) + spike_exp: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=3) + s4_exp: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=3) + + # S4 vaiables + s4_state: np.ndarray = LavaPyType(np.ndarray, float) + a: np.ndarray = LavaPyType(np.ndarray, float) + b: np.ndarray = LavaPyType(np.ndarray, float) + c: np.ndarray = LavaPyType(np.ndarray, float) + + def run_spk(self) -> None: + # Receive synaptic input + a_in_data = self.a_in.recv() + s_out = self.dynamics(a_in_data) + self.s_out.send(s_out) + + +@implements(proc=SigmaS4dDeltaLayer, protocol=LoihiProtocol) +class SubDenseLayerModel(AbstractSubProcessModel): + def __init__(self, proc): + """Builds (Sparse -> S4D -> Sparse) connection of the process.""" + conn_weights = proc.proc_params.get("conn_weights") + shape = proc.proc_params.get("shape") + state_exp = proc.proc_params.get("state_exp") + num_message_bits = proc.proc_params.get("num_message_bits") + s4_exp = proc.proc_params.get("s4_exp") + d_states = proc.proc_params.get("d_states") + a = proc.proc_params.get("a") + b = proc.proc_params.get("b") + c = proc.proc_params.get("c") + vth = proc.proc_params.get("vth") + + # Instantiate processes + self.sparse1 = Sparse(weights=conn_weights.T, weight_exp=state_exp, + num_message_bits=num_message_bits) + self.sigma_S4d_delta = SigmaS4dDelta(shape=(shape[0] * d_states,), + vth=vth, + state_exp=state_exp, + s4_exp=s4_exp, + a=a, + b=b, + c=c) + self.sparse2 = Sparse(weights=conn_weights, weight_exp=state_exp, + num_message_bits=num_message_bits) + + # Make connections Sparse -> SigmaS4Delta -> Sparse + proc.in_ports.s_in.connect(self.sparse1.in_ports.s_in) + self.sparse1.out_ports.a_out.connect(self.sigma_S4d_delta.in_ports.a_in) + self.sigma_S4d_delta.out_ports.s_out.connect(self.sparse2.s_in) + self.sparse2.out_ports.a_out.connect(proc.out_ports.a_out) + + # Set aliases + proc.vars.a.alias(self.sigma_S4d_delta.vars.a) + proc.vars.b.alias(self.sigma_S4d_delta.vars.b) + proc.vars.c.alias(self.sigma_S4d_delta.vars.c) + proc.vars.s4_state.alias(self.sigma_S4d_delta.vars.s4_state) diff --git a/src/lava/proc/s4d/process.py b/src/lava/proc/s4d/process.py new file mode 100644 index 000000000..a99d3e431 --- /dev/null +++ b/src/lava/proc/s4d/process.py @@ -0,0 +1,244 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import typing as ty +import numpy as np +from lava.magma.core.process.process import AbstractProcess +from lava.magma.core.process.variable import Var +from lava.magma.core.process.ports.ports import InPort, OutPort +from lava.proc.sdn.process import ActivationMode, SigmaDelta + + +class S4d(AbstractProcess): + def __init__( + self, + shape: ty.Tuple[int, ...], + a: float, + b: float, + c: float, + s4_state: ty.Optional[int] = 0, + s4_exp: ty.Optional[int] = 0, + inp_exp: ty.Optional[int] = 0) -> None: + """ + Neuron process that implements S4D (described by + Gu et al., 2022) dynamics. + + This process simulates the behavior of a linear time-invariant system + with diagonal state-space representation. + The state-space equations are given by: + s4_state_{k+1} = A * s4_state_k + B * inp_k + act_k = C * s4_state_k + + where: + - s4_state_k is the state vector at time step k, + - inp_k is the input vector at time step k, + - act_k is the output vector at time step k, + - A is the diagonal state matrix, + - B is the diagonal input matrix, + - C is the diagonal output matrix. + + Parameters + ---------- + shape: Tuple + Shape of the sigma process. + vth: int or float + Threshold of the delta encoder. + a: np.ndarray + Diagonal elements of the state matrix of the S4D model. + b: np.ndarray + Diagonal elements of the input matrix of the S4D model. + c: np.ndarray + Diagonal elements of the output matrix of the S4D model. + s4_state: int or float + Initial state of the S4D model. + s4_exp: int + Scaling exponent with base 2 for the S4 state variables. + Note: This should only be used for nc models. + Default is 0. + inp_exp: int + Bit precision of the input signal. + Note: This should only be used for nc models. + Default is 0. + """ + + super().__init__(shape=shape, + a=a, + b=b, + c=c, + s4_state=s4_state, + s4_exp=s4_exp, + inp_exp=inp_exp) + # Ports + self.a_in = InPort(shape=shape) + self.s_out = OutPort(shape=shape) + + # Variables for S4 + self.a = Var(shape=shape, init=a) + self.b = Var(shape=shape, init=b) + self.c = Var(shape=shape, init=c) + self.s4_state = Var(shape=shape, init=s4_state) + self.s4_exp = Var(shape=(1,), init=s4_exp) + self.inp_exp = Var(shape=(1,), init=inp_exp) + + @property + def shape(self) -> ty.Tuple[int, ...]: + """Return shape of the Process.""" + return self.proc_params['shape'] + + +class SigmaS4dDelta(SigmaDelta, AbstractProcess): + def __init__( + self, + shape: ty.Tuple[int, ...], + vth: ty.Union[int, float], + a: float, + b: float, + c: float, + state_exp: ty.Optional[int] = 0, + s4_exp: ty.Optional[int] = 0) -> None: + """ + Sigma delta neuron process that implements S4D (described by + Gu et al., 2022) dynamics as its activation function. + + This process simulates the behavior of a linear time-invariant system + with diagonal state-space representation. + The state-space equations are given by: + s4_state_{k+1} = A * s4_state_k + B * inp_k + act_k = C * s4_state_k + + where: + - s4_state_k is the state vector at time step k, + - inp_k is the input vector at time step k, + - act_k is the output vector at time step k, + - A is the diagonal state matrix, + - B is the diagonal input matrix, + - C is the diagonal output matrix. + + Parameters + ---------- + shape: Tuple + Shape of the sigma process. + vth: int or float + Threshold of the delta encoder. + a: np.ndarray + Diagonal elements of the state matrix of the S4D model. + b: np.ndarray + Diagonal elements of the input matrix of the S4D model. + c: np.ndarray + Diagonal elements of the output matrix of the S4D model. + state_exp: int + Scaling exponent with base 2 for the reconstructed sigma variables. + Note: This should only be used for nc models. + Default is 0. + s4_exp: int + Scaling exponent with base 2 for the S4 state variables. + Note: This should only be used for nc models. + Default is 0. + """ + + super().__init__(shape=shape, + vth=vth, + a=a, + b=b, + c=c, + s4_state=0, + state_exp=state_exp, + s4_exp=s4_exp) + + # Variables for S4 + self.a = Var(shape=shape, init=a) + self.b = Var(shape=shape, init=b) + self.c = Var(shape=shape, init=c) + self.s4_state = Var(shape=shape, init=0) + self.s4_exp = Var(shape=(1,), init=s4_exp) + + +class SigmaS4dDeltaLayer(AbstractProcess): + def __init__( + self, + shape: ty.Tuple[int, ...], + vth: ty.Union[int, float], + a: float, + b: float, + c: float, + d_states: ty.Optional[int] = 1, + s4_exp: ty.Optional[int] = 0, + num_message_bits: ty.Optional[int] = 24, + state_exp: ty.Optional[int] = 0) -> None: + """ + Combines S4D neuron with Sparse Processes that allow for multiple + d_states. + + Connectivity: Sparse -> SigmaS4dDelta -> Sparse. + Relieves user from computing required connection weights for multiple + d_states. + + Parameters + ---------- + shape: Tuple + Shape of the sigma process. + vth: int or float + Threshold of the delta encoder. + a: np.ndarray + Diagonal elements of the state matrix of the S4D model. + b: np.ndarray + Diagonal elements of the input matrix of the S4D model. + c: np.ndarray + Diagonal elements of the output matrix of the S4D model. + d_states: int + Number of hidden states of the S4D model. + Default is 1. + state_exp: int + Scaling exponent with base 2 for the reconstructed sigma variables. + Note: Only relevant for nc model. + Default is 0. + num_message_bits: int + Number of message bits to be used in Sparse connection processes. + Note: Only relevant for nc model. + s4_exp: int + Scaling exponent with base 2 for the S4 state variables. + Note: Only relevant for nc model. + Default is 0. + """ + + # Automatically takes care of expansion and reduction of dimensionality + # for multiple hidden states (d_states) + conn_weights = np.kron(np.eye(shape[0]), np.ones(d_states)) + s4_state = 0 + super().__init__(shape=shape, + vth=vth, + a=a, + b=b, + c=c, + s4_exp=s4_exp, + s4_state=s4_state, + conn_weights=conn_weights, + num_message_bits=num_message_bits, + d_states=d_states, + state_exp=state_exp, + act_mode=ActivationMode.UNIT) + + # Ports + self.s_in = InPort(shape=shape) + self.a_out = OutPort(shape=shape) + + # General variables + self.state_exp = Var(shape=(1,), init=state_exp) + + # Variables for S4 + self.a = Var(shape=(shape[0] * d_states,), init=a) + self.b = Var(shape=(shape[0] * d_states,), init=b) + self.c = Var(shape=(shape[0] * d_states,), init=c) + self.s4_state = Var(shape=(shape[0] * d_states,), init=0) + self.S4_exp = Var(shape=(1,), init=s4_exp) + + # Variables for connecting Dense processes + # Project input_dim to input_dim * d_states + self.conn_weights = Var(shape=shape, init=conn_weights) + self.num_message_bits = Var(shape=(1,), init=num_message_bits) + + @property + def shape(self) -> ty.Tuple[int, ...]: + """Return shape of the Process.""" + return self.proc_params['shape'] diff --git a/src/lava/proc/sdn/process.py b/src/lava/proc/sdn/process.py index 32f083247..6de494706 100644 --- a/src/lava/proc/sdn/process.py +++ b/src/lava/proc/sdn/process.py @@ -126,7 +126,8 @@ def __init__( act_mode: ty.Optional[ActivationMode] = ActivationMode.RELU, cum_error: ty.Optional[bool] = False, spike_exp: ty.Optional[int] = 0, - state_exp: ty.Optional[int] = 0) -> None: + state_exp: ty.Optional[int] = 0, + **kwargs) -> None: """Sigma delta neuron process. At the moment only ReLu activation is supported. Spike mechanism based on accumulated error is also supported. @@ -173,7 +174,7 @@ def __init__( """ super().__init__(shape=shape, vth=vth, bias=bias, act_mode=act_mode, cum_error=cum_error, - spike_exp=spike_exp, state_exp=state_exp) + spike_exp=spike_exp, state_exp=state_exp, **kwargs) # scaling factor for fixed precision scaling vth = vth * (1 << (spike_exp + state_exp)) bias = bias * (1 << (spike_exp + state_exp)) diff --git a/src/lava/proc/sparse/process.py b/src/lava/proc/sparse/process.py index 0f702d398..b584380d7 100644 --- a/src/lava/proc/sparse/process.py +++ b/src/lava/proc/sparse/process.py @@ -69,7 +69,7 @@ def __init__(self, log_config=log_config, **kwargs) - weights = self._create_csr_matrix_from_weights(weights) + weights = self._create_csr_matrix(weights) shape = weights.shape # Ports @@ -77,18 +77,18 @@ def __init__(self, self.a_out = OutPort(shape=(shape[0],)) # Variables - self.weights = Var(shape=shape, init=weights) + self.weights = Var(shape=shape, init=weights.copy()) self.a_buff = Var(shape=(shape[0],), init=0) self.num_message_bits = Var(shape=(1,), init=num_message_bits) @staticmethod - def _create_csr_matrix_from_weights(weights): + def _create_csr_matrix(matrix): # Transform weights to csr matrix - if isinstance(weights, np.ndarray): - weights = csr_matrix(weights) + if isinstance(matrix, np.ndarray): + matrix = csr_matrix(matrix) else: - weights = weights.tocsr() - return weights + matrix = matrix.tocsr() + return matrix class LearningSparse(LearningConnectionProcess, Sparse): @@ -160,6 +160,8 @@ class LearningSparse(LearningConnectionProcess, Sparse): def __init__(self, *, weights: ty.Union[spmatrix, np.ndarray], + tag_2: ty.Optional[ty.Union[spmatrix, np.ndarray]] = None, + tag_1: ty.Optional[ty.Union[spmatrix, np.ndarray]] = None, name: ty.Optional[str] = None, num_message_bits: ty.Optional[int] = 0, log_config: ty.Optional[LogConfig] = None, @@ -172,6 +174,8 @@ def __init__(self, learning_rule.x1_impulse = 0 super().__init__(weights=weights, + tag_2=tag_2, + tag_1=tag_1, shape=weights.shape, num_message_bits=num_message_bits, name=name, @@ -180,17 +184,23 @@ def __init__(self, graded_spike_cfg=graded_spike_cfg, **kwargs) - weights = self._create_csr_matrix_from_weights(weights) - shape = weights.shape + if tag_2 is None: + tag_2 = np.zeros(weights.shape) - # Ports - self.s_in = InPort(shape=(shape[1],)) - self.a_out = OutPort(shape=(shape[0],)) + if tag_1 is None: + tag_1 = np.zeros(weights.shape) - # Variables - self.weights = Var(shape=shape, init=weights) - self.a_buff = Var(shape=(shape[0],), init=0) - self.num_message_bits = Var(shape=(1,), init=num_message_bits) + tag_2 = self._create_csr_matrix(tag_2) + tag_1 = self._create_csr_matrix(tag_1) + + self.tag_2.init = tag_2.copy() + self.tag_1.init = tag_1.copy() + + self.proc_params["x_idx_active_syn_vars"] = { + "weights": weights.nonzero()[1], + "tag_2": tag_2.nonzero()[1], + "tag_1": tag_1.nonzero()[1] + } class DelaySparse(Sparse): diff --git a/src/lava/proc/spiker/process.py b/src/lava/proc/spiker/process.py index 18af830a1..05657fac5 100644 --- a/src/lava/proc/spiker/process.py +++ b/src/lava/proc/spiker/process.py @@ -3,6 +3,7 @@ # See: https://spdx.org/licenses/ import typing as ty +import numpy.typing as npty import numpy as np from lava.magma.core.process.ports.ports import OutPort @@ -19,6 +20,7 @@ class Spiker(AbstractProcess): Shape of the population of process units. period : int Number of timesteps between subsequent emissions of payload. + Note that the first spike is emitted at time step period + 1. payload : int A value to be send with every output message. name : str @@ -39,3 +41,74 @@ def __init__(self, *, self.rate = Var(shape=shape, init=period) self.counter = Var(shape=shape, init=np.zeros(shape).astype(int)) self.payload = Var(shape=shape, init=payload) + + +class Spiker32bit(AbstractProcess): + """Process emitting a specified payload at a given rate. + Provides 32bit payloads, and separate payloads for each neuron. + Other than the default Spiker process, this process actually starts spiking + at timestep = period. + + Parameters + ---------- + shape : tuple(int) + Shape of the population of process units. + period : int + Number of timesteps between subsequent emissions of payload. + payload : int + A value to be send with every output message. + Can be in [0, 2**32 - 1] if signed==False, + or in [-2**31, 2**31 - 1] if signed==True. + signed : bool + True if signed payload, False otherwise. + name : str + Name of the Process. Default is 'Process_ID', where ID is an + integer value that is determined automatically. + log_config : LogConfig + Configuration options for logging. + """ + + def __init__(self, *, + shape: ty.Tuple[int, ...] = (1,), + period: ty.Union[int, npty.ArrayLike] = 1, + payload: ty.Union[int, npty.ArrayLike] = 1, + name: ty.Optional[str] = None, + log_config: ty.Optional[LogConfig] = None) -> None: + + signed = self._input_validation(payload) + + if np.isscalar(period): + period = np.array([period], dtype=int) + else: + period = period.astype(int) + if np.isscalar(payload): + payload = np.array([payload]) + else: + payload = payload.astype(int) + + super().__init__(shape=shape, + period=period, + payload=payload, + signed=signed, + name=name, log_config=log_config) + self.s_out = OutPort(shape=shape) + self.counter = Var(shape=shape, init=np.zeros(shape).astype(int) + 1) + + def _input_validation(self, payload) -> bool: + payload_min = np.min(payload) + payload_max = np.max(payload) + signed = payload_min < 0 + + if payload_min < -2 ** 31: + raise ValueError( + f"The payload must be >= -2**31, but the smallest value is " + f"{payload_min}.") + + payload_max_allowed = 2 ** 31 - 1 if signed else 2 ** 32 - 1 + + if payload_max > payload_max_allowed: + raise ValueError( + f"The payload must be <= {payload_max_allowed}, but the " + f"largest value is {payload_max}.") + + return signed diff --git a/src/lava/utils/weightutils.py b/src/lava/utils/weightutils.py index 0230da93e..314c06540 100644 --- a/src/lava/utils/weightutils.py +++ b/src/lava/utils/weightutils.py @@ -249,7 +249,9 @@ def truncate_weights(weights: ty.Union[np.ndarray, spmatrix], def clip_weights(weights: ty.Union[np.ndarray, spmatrix], sign_mode: SignMode, - num_bits: int) -> ty.Union[np.ndarray, spmatrix]: + num_bits: int, + learning_simulation: ty.Optional[bool] = False) \ + -> ty.Union[np.ndarray, spmatrix]: """Truncate the least significant bits of the weight matrix given the sign mode and number of weight bits. @@ -261,6 +263,9 @@ def clip_weights(weights: ty.Union[np.ndarray, spmatrix], Sign mode to use for truncation. num_bits : int Number of bits to use to clip the weights to. + learning_simulation : bool, optional + Boolean flag, specifying if this method is used in context of learning + (in simulation). Returns ------- @@ -276,7 +281,7 @@ def clip_weights(weights: ty.Union[np.ndarray, spmatrix], weights = -weights min_wgt = (-2 ** num_bits) * mixed_flag - max_wgt = 2 ** num_bits - 1 + max_wgt = 2 ** num_bits - 1 - learning_simulation * mixed_flag if isinstance(weights, np.ndarray): weights = np.clip(weights, min_wgt, max_wgt) diff --git a/tests/lava/frameworks/__init__.py b/tests/lava/frameworks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/lava/frameworks/test_frameworks.py b/tests/lava/frameworks/test_frameworks.py new file mode 100644 index 000000000..e833995c3 --- /dev/null +++ b/tests/lava/frameworks/test_frameworks.py @@ -0,0 +1,17 @@ +# Copyright (C) 2023 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import unittest + + +class TestFrameworks(unittest.TestCase): + """Tests for framework import.""" + + def test_frameworks_loihi2_import(self): + """Tests if framework import fails.""" + import lava.frameworks.loihi2 as lv + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/lava/magma/compiler/test_compiler.py b/tests/lava/magma/compiler/test_compiler.py index 1046253c3..876def248 100644 --- a/tests/lava/magma/compiler/test_compiler.py +++ b/tests/lava/magma/compiler/test_compiler.py @@ -170,6 +170,10 @@ def create_mock_proc_groups() -> ty.List[ProcGroup]: py_pg2_p1 = Mock(spec_set=AbstractProcess()) py_pg2_p2 = Mock(spec_set=AbstractProcess()) + py_pg1_p1.configure_mock(name='py_pg1_p1') + py_pg2_p1.configure_mock(name='py_pg2_p1') + py_pg2_p2.configure_mock(name='py_pg2_p2') + proc_list = [py_pg1_p1, py_pg2_p1, py_pg2_p2] proc_model_types = [ @@ -213,7 +217,8 @@ def create_patches( and the compile() method returns the given ChannelMap unchanged. .""" - def compile_return(channel_map: ChannelMap) -> ChannelMap: + def compile_return(channel_map: ChannelMap, + partitioning=None) -> ChannelMap: return channel_map py_patch = patch( @@ -387,13 +392,13 @@ def test_compile_proc_group_single_loop(self) -> None: subcompilers = [py_proc_compiler] # Call the method to be tested. - self.compiler._compile_proc_group(subcompilers, channel_map) + self.compiler._compile_proc_group(subcompilers, channel_map, None) # Check that it called compile() on every SubCompiler instance # exactly once. After that, the while loop should exit because the # ChannelMap instance has not changed. for sc in subcompilers: - sc.compile.assert_called_once_with({}) + sc.compile.assert_called_once_with({}, None) def test_compile_proc_group_multiple_loops(self) -> None: """Test whether the correct methods are called on all objects when @@ -420,13 +425,15 @@ def test_compile_proc_group_multiple_loops(self) -> None: subcompilers = [py_proc_compiler] # Call the method to be tested. - self.compiler._compile_proc_group(subcompilers, channel_map) + self.compiler._compile_proc_group(subcompilers, channel_map, + None) # Check that it called compile() on every SubCompiler instance # exactly once. After that, the while loop should exit because the # ChannelMap instance has not changed. for sc in subcompilers: - sc.compile.assert_called_with({**channel_map1, **channel_map2}) + sc.compile.assert_called_with({**channel_map1, **channel_map2}, + None) self.assertEqual(sc.compile.call_count, 3) def test_extract_proc_builders(self) -> None: diff --git a/tests/lava/magma/runtime/test_external_pipe_io.py b/tests/lava/magma/runtime/test_external_pipe_io.py new file mode 100644 index 000000000..0e723fbad --- /dev/null +++ b/tests/lava/magma/runtime/test_external_pipe_io.py @@ -0,0 +1,96 @@ +# Copyright (C) 2022 Intel Corporation +# SPDX-License-Identifier: LGPL 2.1 or later +# See: https://spdx.org/licenses/ +import threading +import unittest +import typing as ty + +import numpy as np + +from lava.magma.core.decorator import implements, requires +from lava.magma.core.model.py.model import PyLoihiProcessModel +from lava.magma.core.model.py.ports import PyOutPort, PyInPort +from lava.magma.core.model.py.type import LavaPyType +from lava.magma.core.process.ports.ports import OutPort, InPort +from lava.magma.core.process.process import AbstractProcess +from lava.magma.core.resources import CPU +from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol +from lava.magma.core.run_conditions import RunSteps +from lava.magma.core.run_configs import Loihi2SimCfg + + +class Process1(AbstractProcess): + def __init__(self, shape_1: ty.Tuple, **kwargs): + super().__init__(shape_1=shape_1, **kwargs) + + self.in_1 = InPort(shape=shape_1) + self.out_1 = OutPort(shape=shape_1) + + +@implements(proc=Process1, protocol=LoihiProtocol) +@requires(CPU) +class LoihiDenseSpkPyProcess1PM(PyLoihiProcessModel): + in_1: PyInPort = LavaPyType(PyInPort.VEC_DENSE, float) + out_1: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) + + def __init__(self, proc_params): + super().__init__(proc_params) + + def run_spk(self): + print(f"Receiving in Process...") + data_1 = self.in_1.recv() + print(f"Received {data_1} in Process...") + + print(f"Sending {data_1} from Process...") + self.out_1.send(data_1) + print(f"Sent {data_1} from Process!") + + +class TestExternalPipeIO(unittest.TestCase): + def test_run_steps_non_blocking(self): + data = [[1], [2], [3], [4], [5]] + + relay = Process1(shape_1=(1,)) + # Control buffer size with buffer_size arg, default is 64 + relay.in_1.flag_external_pipe() + # Control buffer size with buffer_size arg, default is 64 + relay.out_1.flag_external_pipe() + + run_cfg = Loihi2SimCfg() + run_condition = RunSteps(num_steps=5, blocking=False) + + def thread_inject_fn() -> None: + for send_data_single_item in data: + print(f"Sending {send_data_single_item} from thread_inject...") + # Use probe() before send() to know whether or not send() will + # block (i.e if the buffer of external_pipe_csp_send_port + # is full). + relay.in_1.external_pipe_csp_send_port.send( + np.array(send_data_single_item)) + print(f"Sent {send_data_single_item} from thread_inject!") + + def thread_extract_fn() -> None: + for _ in range(len(data)): + print(f"Receiving in thread_extract...") + # Use probe() before recv() to know whether or not recv() will + # block (i.e if the buffer of external_pipe_csp_recv_port + # is empty). + received_data = relay.out_1.external_pipe_csp_recv_port.recv() + print(f"Received {received_data} in thread_extract!") + + thread_inject = threading.Thread(target=thread_inject_fn, + daemon=True) + thread_extract = threading.Thread(target=thread_extract_fn, + daemon=True) + + relay.run(condition=run_condition, run_cfg=run_cfg) + + thread_inject.start() + thread_extract.start() + + relay.wait() + relay.stop() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/lava/networks/__init__.py b/tests/lava/networks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/lava/networks/test_networks.py b/tests/lava/networks/test_networks.py new file mode 100644 index 000000000..317977c92 --- /dev/null +++ b/tests/lava/networks/test_networks.py @@ -0,0 +1,28 @@ +# Copyright (C) 2023 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import unittest +import numpy as np +from scipy.sparse import csr_matrix + +import lava.frameworks.loihi2 as lv + + +class TestNetworks(unittest.TestCase): + """Tests for LVA Networks.""" + + def test_networks_instantiate(self): + """Tests if LVA Networks can be instantiated.""" + inputvec = lv.InputVec(np.ones((1,)), shape=(1,)) + outputvec = lv.OutputVec(shape=(1,), buffer=1) + threshvec = lv.GradedVec(shape=(1,)) + gradeddense = lv.GradedDense(weights=np.ones((1, 1))) + gradedsparse = lv.GradedSparse(weights=csr_matrix(np.ones((1, 1)))) + productvec = lv.ProductVec(shape=(1,)) + lifvec = lv.LIFVec(shape=(1,)) + normnet = lv.NormalizeNet(shape=(1,)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/lava/proc/atrlif/__init__.py b/tests/lava/proc/atrlif/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/lava/proc/atrlif/test_models.py b/tests/lava/proc/atrlif/test_models.py new file mode 100644 index 000000000..6db21b91f --- /dev/null +++ b/tests/lava/proc/atrlif/test_models.py @@ -0,0 +1,696 @@ +# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024 Jannik Luboeinski +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import unittest +import numpy as np + +from lava.magma.core.decorator import implements, requires, tag +from lava.magma.core.model.py.model import PyLoihiProcessModel +from lava.magma.core.model.py.ports import PyOutPort, PyInPort +from lava.magma.core.model.py.type import LavaPyType +from lava.magma.core.process.ports.ports import OutPort, InPort +from lava.magma.core.process.process import AbstractProcess +from lava.magma.core.process.variable import Var +from lava.magma.core.resources import CPU +from lava.magma.core.run_configs import RunConfig +from lava.magma.core.run_conditions import RunSteps +from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol +from lava.proc.atrlif.process import ATRLIF + + +class AtrlifRunConfig(RunConfig): + """Run configuration selects appropriate ATRLIF ProcessModel based on tag: + floating point precision or Loihi bit-accurate fixed point precision""" + def __init__(self, custom_sync_domains=None, select_tag='fixed_pt'): + super().__init__(custom_sync_domains=custom_sync_domains) + self.select_tag = select_tag + + def select(self, proc, proc_models): + for pm in proc_models: + if self.select_tag in pm.tags: + return pm + raise AssertionError("No legal ProcessModel found.") + + +class VecSendProcess(AbstractProcess): + """ + Process of a user-defined shape that sends an arbitrary vector + + Parameters + ---------- + shape: tuple, shape of the process + vec_to_send: np.ndarray, vector of spike values to send + send_at_times: np.ndarray, vector bools. Send the `vec_to_send` at times + when there is a True + """ + def __init__(self, **kwargs): + super().__init__() + shape = kwargs.pop("shape", (1,)) + vec_to_send = kwargs.pop("vec_to_send") + send_at_times = kwargs.pop("send_at_times") + num_steps = kwargs.pop("num_steps", 1) + self.shape = shape + self.num_steps = num_steps + self.vec_to_send = Var(shape=shape, init=vec_to_send) + self.send_at_times = Var(shape=(num_steps,), init=send_at_times) + self.s_out = OutPort(shape=shape) + + +class VecRecvProcess(AbstractProcess): + """ + Process that receives arbitrary vectors + + Parameters + ---------- + shape: tuple, shape of the process + """ + def __init__(self, **kwargs): + super().__init__() + shape = kwargs.get("shape", (1,)) + self.shape = shape + self.s_in = InPort(shape=(shape[1],)) + self.spk_data = Var(shape=shape, init=0) # This Var expands with time + + +@implements(proc=VecSendProcess, protocol=LoihiProtocol) +@requires(CPU) +# Following tag is needed to discover the ProcessModel using AtrlifRunConfig +@tag('floating_pt') +class PyVecSendModelFloat(PyLoihiProcessModel): + s_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) + vec_to_send: np.ndarray = LavaPyType(np.ndarray, float) + send_at_times: np.ndarray = LavaPyType(np.ndarray, bool, precision=1) + + def run_spk(self): + """ + Send `spikes_to_send` if current time-step requires it + """ + if self.send_at_times[self.time_step - 1]: + self.s_out.send(self.vec_to_send) + else: + self.s_out.send(np.zeros_like(self.vec_to_send)) + + +@implements(proc=VecSendProcess, protocol=LoihiProtocol) +@requires(CPU) +# Following tag is needed to discover the ProcessModel using AtrlifRunConfig +@tag('fixed_pt') +class PyVecSendModelFixed(PyLoihiProcessModel): + s_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, np.int16, precision=16) + vec_to_send: np.ndarray = LavaPyType(np.ndarray, np.int16, precision=16) + send_at_times: np.ndarray = LavaPyType(np.ndarray, bool, precision=1) + + def run_spk(self): + """ + Send `spikes_to_send` if current time-step requires it + """ + if self.send_at_times[self.time_step - 1]: + self.s_out.send(self.vec_to_send) + else: + self.s_out.send(np.zeros_like(self.vec_to_send)) + + +@implements(proc=VecRecvProcess, protocol=LoihiProtocol) +@requires(CPU) +# Following tag is needed to discover the ProcessModel using AtrlifRunConfig +@tag('floating_pt') +class PySpkRecvModelFloat(PyLoihiProcessModel): + s_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, bool, precision=1) + spk_data: np.ndarray = LavaPyType(np.ndarray, float) + + def run_spk(self): + """Receive spikes and store in an internal variable""" + spk_in = self.s_in.recv() + self.spk_data[self.time_step - 1, :] = spk_in + + +@implements(proc=VecRecvProcess, protocol=LoihiProtocol) +@requires(CPU) +# Following tag is needed to discover the ProcessModel using AtrlifRunConfig +@tag('fixed_pt') +class PySpkRecvModelFixed(PyLoihiProcessModel): + s_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, bool, precision=1) + spk_data: np.ndarray = LavaPyType(np.ndarray, int, precision=1) + + def run_spk(self): + """Receive spikes and store in an internal variable""" + spk_in = self.s_in.recv() + self.spk_data[self.time_step - 1, :] = spk_in + + +class TestATRLIFProcessModelsFloat(unittest.TestCase): + """ + Tests for floating point ProcessModels of ATRLIF, resembling the + existing tests for the LIF process. + """ + def test_float_pm_no_decay(self): + """ + Tests floating point ATRLIF ProcessModel with no current or voltage + decay and neurons driven by internal biases. + """ + shape = (10,) + num_steps = 50 + # Set up external input to 0 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=np.zeros(shape, dtype=float), + send_at_times=np.ones((num_steps,), dtype=bool)) + # `delta_i` and `delta_v` = 0 => bias driven neurons spike first after + # `theta_0 / bias` time steps, then less often due to the refractor- + # iness. For the test implementation below, `theta_0` has to be a + # multiple of `bias`. + bias = 2 + theta_0 = 4 + neur = ATRLIF(shape=shape, + delta_i=0., + delta_v=0., + delta_theta=0., + delta_r=0., + theta_0=theta_0, + theta=theta_0, + theta_step=0., + bias_mant=bias * np.ones(shape, dtype=float)) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = AtrlifRunConfig(select_tag='floating_pt') + neur.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + neur.stop() + # Compute the number of time steps until the first spike + t_spike_0 = theta_0 // bias + # Compute the following number of time steps until the second spike + # (according to `bias * (t_spike_0 + t_spike_refr) - 2 * theta_0 >= + # theta_0`) + t_spike_refr = 3 * theta_0 // bias - t_spike_0 + # Gold standard for the test + expected_spk_data = np.zeros((t_spike_0 + t_spike_refr + 1, shape[0])) + expected_spk_data[t_spike_0 - 1:t_spike_0 + t_spike_refr + 1: + t_spike_refr, :] = 1. + spk_data_through_run_needed = \ + spk_data_through_run[0:t_spike_0 + t_spike_refr + 1, :] + self.assertTrue(np.all(expected_spk_data + == spk_data_through_run_needed)) + + def test_float_pm_impulse_delta_i(self): + """ + Tests floating point ATRLIF ProcessModel's impulse response with no + voltage decay and input activation at the very first time-step. + """ + # Use a single neuron + shape = (1,) + num_steps = 8 + # Send activation of 128. at timestep = 1 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=(2 ** 7) * np.ones(shape, + dtype=float), + send_at_times=np.array([True, False, False, + False, False, False, + False, False])) + # Set up no bias, no voltage decay. Current decay = 0.5. + # Set up high constant threshold, such that there are no output spikes. + neur = ATRLIF(shape=shape, + delta_i=0.5, + delta_v=0., + delta_theta=0., + delta_r=0., + theta_0=256., + theta=256., + theta_step=0., + bias_mant=np.zeros(shape, dtype=float)) + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure to run 1 step at a time + rcnd = RunSteps(num_steps=1) + rcfg = AtrlifRunConfig(select_tag='floating_pt') + neur_i = [] + # Run 1 timestep at a time and collect state variable i + for _ in range(num_steps): + neur.run(condition=rcnd, run_cfg=rcfg) + neur_i.append(neur.i.get()[0]) + neur.stop() + # Gold standard for testing: current decay of 0.5 should halve the + # current every time-step + expected_i_timeseries = [2. ** (7 - j) for j in range(8)] + self.assertListEqual(expected_i_timeseries, neur_i) + + def test_float_pm_impulse_delta_v(self): + """ + Tests floating point ATRLIF ProcessModel's impulse response with no + current decay and input activation at the very first time-step. + """ + # Use a single neuron + shape = (1,) + num_steps = 8 + # Send activation of 128. at timestep = 1 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=(2 ** 7) * np.ones(shape, + dtype=float), + send_at_times=np.array([True, False, False, + False, False, False, + False, False])) + # Set up no bias, no current decay. Voltage decay = 0.5. + # Set up high constant threshold, such that there are no output spikes. + neur = ATRLIF(shape=shape, + delta_i=0., + delta_v=0.5, + delta_theta=0., + delta_r=0., + theta_0=256., + theta=256., + theta_step=0., + bias_mant=np.zeros(shape, dtype=float)) + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure to run 1 step at a time + rcnd = RunSteps(num_steps=1) + rcfg = AtrlifRunConfig(select_tag='floating_pt') + neur_v = [] + # Run 1 timestep at a time and collect state variable v + for _ in range(num_steps): + neur.run(condition=rcnd, run_cfg=rcfg) + neur_v.append(neur.v.get()[0]) + neur.stop() + # Gold standard for testing: voltage decay of 0.5 should integrate + # the voltage from 128. to 255., with steps of 64., 32., 16., etc. + expected_v_timeseries = [128., 192., 224., 240., + 248., 252., 254., 255.] + self.assertListEqual(expected_v_timeseries, neur_v) + + def test_float_pm_instant_theta_decay(self): + """ + Tests floating point ATRLIF ProcessModel's behavior for instant decay + of the threshold variable in the presence of constant bias. + """ + # Use a single neuron + shape = (1,) + num_steps = 20 + # Set up external input to 0 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=np.zeros(shape, dtype=float), + send_at_times=np.ones((num_steps,), dtype=bool)) + # `delta_i` and `delta_v` = 0 => bias driven neurons spike first after + # `theta_0 / bias` time steps, then less often due to the refractor- + # iness. For the test implementation below, `theta_0` has to be a + # multiple of `bias`. Following a spike, the threshold `theta` is + # increased tremendously (by 10.), but this remains without effect + # due to the instant decay (`delta_theta=1.`). + bias = 2 + theta_0 = 4 + neur = ATRLIF(shape=shape, + delta_i=0., + delta_v=0., + delta_theta=1., + delta_r=0., + theta_0=theta_0, + theta=theta_0, + theta_step=10., + bias_mant=bias * np.ones(shape, dtype=float)) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = AtrlifRunConfig(select_tag='floating_pt') + neur.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + neur.stop() + # Compute the number of time steps until the first spike + t_spike_0 = theta_0 // bias + # Compute the following number of time steps until the second spike + # (according to `bias * (t_spike_0 + t_spike_refr) - 2 * theta_0 >= + # theta_0`) + t_spike_refr = 3 * theta_0 // bias - t_spike_0 + # Gold standard for the test + expected_spk_data = np.zeros((t_spike_0 + t_spike_refr + 1, shape[0])) + expected_spk_data[t_spike_0 - 1:t_spike_0 + t_spike_refr + 1: + t_spike_refr, :] = 1. + spk_data_through_run_needed = \ + spk_data_through_run[0:t_spike_0 + t_spike_refr + 1, :] + self.assertTrue(np.all(expected_spk_data + == spk_data_through_run_needed)) + + def test_float_pm_instant_r_decay(self): + """ + Tests floating point ATRLIF ProcessModel's behavior for instant decay + of the refractory variable in the presence of constant bias. + """ + # Use a single neuron + shape = (1,) + num_steps = 20 + # Set up external input to 0 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=np.zeros(shape, dtype=float), + send_at_times=np.ones((num_steps,), dtype=bool)) + # `delta_i` and `delta_v` = 0 => bias driven neurons spike first after + # `theta_0 / bias` time steps. Following a spike, the threshold `theta` + # is automatically increased by `2 * theta`, but this remains without + # effect due to the instant decay (`delta_r=1.`). + bias = 8 + theta_0 = 16 + neur = ATRLIF(shape=shape, + delta_i=0., + delta_v=0., + delta_theta=0., + delta_r=1., + theta_0=theta_0, + theta=theta_0, + theta_step=0., + bias_mant=bias * np.ones(shape, dtype=float)) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = AtrlifRunConfig(select_tag='floating_pt') + neur.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + neur.stop() + # Compute the number of time steps until the first spike + t_spike_0 = theta_0 // bias + # Compute the following number of time steps until the second spike + # (according to `bias * (t_spike_0 + t_spike_refr) >= theta_0`) + t_spike_refr = theta_0 // bias - t_spike_0 + 1 + # Gold standard for the test + expected_spk_data = np.zeros((t_spike_0 + t_spike_refr + 1, shape[0])) + expected_spk_data[t_spike_0 - 1:t_spike_0 + t_spike_refr + 1: + t_spike_refr, :] = 1. + spk_data_through_run_needed = \ + spk_data_through_run[0:t_spike_0 + t_spike_refr + 1, :] + self.assertTrue(np.all(expected_spk_data + == spk_data_through_run_needed)) + + +class TestATRLIFProcessModelsFixed(unittest.TestCase): + """ + Tests for fixed point ProcessModels of ATRLIF (which are bit-accurate + with Loihi hardware), resembling the existing tests for the LIF process. + """ + def test_bitacc_pm_no_decay(self): + """ + Tests fixed point ATRLIF ProcessModel (bit-accurate + with Loihi hardware) with no current or voltage + decay and neurons driven by internal biases. + """ + shape = (10,) + num_steps = 50 + # Set up external input to 0 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=np.zeros(shape, dtype=np.int16), + send_at_times=np.ones((num_steps,), dtype=bool)) + # Set up bias = 2 * 2**6 = 128 and threshold = 8<<6 + # `delta_i` and `delta_v` = 0 => bias driven neurons spike first after + # `theta_0 / bias` time steps, then less often due to the refractor- + # iness. For the test implementation below, `theta_0` has to be a + # multiple of `bias`. + bias = 4 + theta_0 = 8 + neur = ATRLIF(shape=shape, + delta_i=0, + delta_v=0, + delta_theta=0, + delta_r=0, + theta_0=theta_0, + theta=theta_0, + theta_step=0, + bias_mant=bias * np.ones(shape, dtype=np.int32), + bias_exp=6 * np.ones(shape, dtype=np.int32)) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = AtrlifRunConfig(select_tag='fixed_pt') + neur.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + neur.stop() + # Compute the number of time steps until the first spike + t_spike_0 = theta_0 // bias + # Compute the following number of time steps until the second spike + # (according to `bias * (t_spike_0 + t_spike_refr) - 2 * theta_0 >= + # theta_0`) + t_spike_refr = 3 * theta_0 // bias - t_spike_0 + # Gold standard for the test + expected_spk_data = np.zeros((t_spike_0 + t_spike_refr + 1, shape[0])) + expected_spk_data[t_spike_0 - 1:t_spike_0 + t_spike_refr + 1: + t_spike_refr, :] = 1. + spk_data_through_run_needed = \ + spk_data_through_run[0:t_spike_0 + t_spike_refr + 1, :] + self.assertTrue(np.all(expected_spk_data + == spk_data_through_run_needed)) + + def test_bitacc_pm_impulse_delta_i(self): + """ + Tests fixed point ATRLIF ProcessModel's impulse response with no + voltage decay and input activation at the very first time-step. + """ + # Use a single neuron + shape = (1,) + num_steps = 8 + # Send activation of 128. at timestep = 1 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=128 * np.ones(shape, dtype=np.int32), + send_at_times=np.array([True, False, False, + False, False, False, + False, False])) + # Set up no bias, no voltage decay. Current decay is a 12-bit + # unsigned variable in Loihi hardware. Therefore, 2**-12 is the + # equivalent of 1. The subtracted 1 is added by default in the + # hardware via the `ds_offset` setting, thereby finally giving + # `delta_i = 2048 = 0.5 * 2**12`. + # Set up threshold high, such that there are no output spikes. By + # default the threshold value here is left-shifted by 6. + neur = ATRLIF(shape=shape, + delta_i=0.5 - (2**-12), + delta_v=0, + delta_theta=0, + delta_r=0, + theta_0=256 * np.ones(shape, dtype=np.int32), + theta=256 * np.ones(shape, dtype=np.int32), + theta_step=0, + bias_mant=np.zeros(shape, dtype=np.int16), + bias_exp=np.ones(shape, dtype=np.int16)) + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure to run 1 step at a time + rcnd = RunSteps(num_steps=1) + rcfg = AtrlifRunConfig(select_tag='fixed_pt') + neur_i = [] + # Run 1 timestep at a time and collect state variable i + for _ in range(num_steps): + neur.run(condition=rcnd, run_cfg=rcfg) + neur_i.append(neur.i.get().astype(np.int32)[0]) + neur.stop() + # Gold standard for testing: current decay of 0.5 should halve the + # current every time-step. + expected_i_timeseries = [1 << (13 - j) for j in range(8)] + # Gold standard for floating point equivalent of the current, + # which would be all Loihi-bit-accurate values right shifted by 6 bits + expected_float_i = [1 << (7 - j) for j in range(8)] + self.assertListEqual(expected_i_timeseries, neur_i) + self.assertListEqual(expected_float_i, np.right_shift(np.array( + neur_i), 6).tolist()) + + def test_bitacc_pm_impulse_delta_v(self): + """ + Tests fixed point ATRLIF ProcessModel's impulse response with no + current decay and input activation at the very first time-step. + """ + # Use a single neuron + shape = (1,) + num_steps = 8 + # Send activation of 128. at timestep = 1 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=128 * np.ones(shape, dtype=np.int32), + send_at_times=np.array([True, False, False, + False, False, False, + False, False])) + # Set up no bias, no current decay. + # Set up threshold high, such that there are no output spikes. + # Threshold provided here is left-shifted by 6-bits. + neur = ATRLIF(shape=shape, + delta_i=0, + delta_v=0.5, + delta_theta=0, + delta_r=0, + theta_0=256 * np.ones(shape, dtype=np.int32), + theta=256 * np.ones(shape, dtype=np.int32), + theta_step=0, + bias_mant=np.zeros(shape, dtype=np.int16), + bias_exp=np.ones(shape, dtype=np.int16)) + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure to run 1 step at a time + rcnd = RunSteps(num_steps=1) + rcfg = AtrlifRunConfig(select_tag='fixed_pt') + neur_v = [] + # Run 1 timestep at a time and collect state variable u + for _ in range(num_steps): + neur.run(condition=rcnd, run_cfg=rcfg) + neur_v.append(neur.v.get().astype(np.int32)[0]) + neur.stop() + # Gold standard for testing: with a voltage decay of 2048, voltage + # should integrate from 128<<6 to 255<<6. But it is slightly smaller, + # because current decay is not exactly 0. Due to the default + # ds_offset = 1 setting in the hardware, current decay = 1. So + # voltage is slightly smaller than 128<<6 to 255<<6. + expected_v_timeseries = [8192, 12286, 14331, 15351, 15859, 16111, + 16235, 16295] + # Gold standard for floating point equivalent of the voltage, + # which would be all Loihi-bit-accurate values right shifted by 6 bits + expected_float_v = [128, 192, 224, 240, 248, 252, 254, 255] + neur_v_float = np.right_shift(np.array(neur_v), 6) + neur_v_float[1:] += 1 # This compensates the drift caused by ds_offset + self.assertListEqual(expected_v_timeseries, neur_v) + self.assertListEqual(expected_float_v, neur_v_float.tolist()) + + def test_bitacc_pm_scaling_of_bias(self): + """ + Tests fixed point ATRLIF ProcessModel's scaling of threshold. + """ + bias_mant = 2 ** 12 - 1 + bias_exp = 5 + # Set up high threshold and high bias current to check for potential + # overflow in effective bias in single neuron. + neur = ATRLIF(shape=(1,), + delta_i=0, + delta_v=0.5, + delta_theta=0, + delta_r=0, + theta_0=2 ** 17, + theta=2 ** 17, + theta_step=0, + bias_mant=bias_mant, + bias_exp=bias_exp) + + rcnd = RunSteps(num_steps=1) + rcfg = AtrlifRunConfig(select_tag='fixed_pt') + + neur.run(condition=rcnd, run_cfg=rcfg) + neur_v = neur.v.get()[0] + neur.stop() + + # Check if neur_v has correct value. + self.assertEqual(neur_v, bias_mant * 2 ** bias_exp) + + def test_fixed_pm_instant_theta_decay(self): + """ + Tests fixed point ATRLIF ProcessModel's behavior for instant decay + of the threshold variable in the presence of constant bias. + """ + # Use a single neuron + shape = (1,) + num_steps = 20 + # Set up external input to 0 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=np.zeros(shape, dtype=float), + send_at_times=np.ones((num_steps,), dtype=bool)) + # `delta_i` and `delta_v` = 0 => bias driven neurons spike first after + # `theta_0 / bias` time steps, then less often due to the refractor- + # iness. For the test implementation below, `theta_0` has to be a + # multiple of `bias`. Following a spike, the threshold `theta` is + # increased tremendously (by 10.), but this remains without effect + # due to the instant decay (`delta_theta=1.`). + bias = 2 + theta_0 = 4 + neur = ATRLIF(shape=shape, + delta_i=0, + delta_v=0, + delta_theta=1, + delta_r=0, + theta_0=theta_0, + theta=theta_0, + theta_step=10, + bias_mant=bias * np.ones(shape, dtype=float)) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = AtrlifRunConfig(select_tag='floating_pt') + neur.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + neur.stop() + # Compute the number of time steps until the first spike + t_spike_0 = theta_0 // bias + # Compute the following number of time steps until the second spike + # (according to `bias * (t_spike_0 + t_spike_refr) - 2 * theta_0 >= + # theta_0`) + t_spike_refr = 3 * theta_0 // bias - t_spike_0 + # Gold standard for the test + expected_spk_data = np.zeros((t_spike_0 + t_spike_refr + 1, shape[0])) + expected_spk_data[t_spike_0 - 1:t_spike_0 + t_spike_refr + 1: + t_spike_refr, :] = 1. + spk_data_through_run_needed = \ + spk_data_through_run[0:t_spike_0 + t_spike_refr + 1, :] + self.assertTrue(np.all(expected_spk_data + == spk_data_through_run_needed)) + + def test_fixed_pm_instant_r_decay(self): + """ + Tests fixed point ATRLIF ProcessModel's behavior for instant decay + of the refractory variable in the presence of constant bias. + """ + # Use a single neuron + shape = (1,) + num_steps = 20 + # Set up external input to 0 + sps = VecSendProcess(shape=shape, num_steps=num_steps, + vec_to_send=np.zeros(shape, dtype=float), + send_at_times=np.ones((num_steps,), dtype=bool)) + # `delta_i` and `delta_v` = 0 => bias driven neurons spike first after + # `theta_0 / bias` time steps. Following a spike, the threshold `theta` + # is automatically increased by `2 * theta`, but this remains without + # effect due to the instant decay (`delta_r=1`). + bias = 8 + theta_0 = 16 + neur = ATRLIF(shape=shape, + delta_i=0, + delta_v=0, + delta_theta=0, + delta_r=1, + theta_0=theta_0, + theta=theta_0, + theta_step=0, + bias_mant=bias * np.ones(shape, dtype=float)) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(neur.a_in) + neur.s_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = AtrlifRunConfig(select_tag='floating_pt') + neur.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + neur.stop() + # Compute the number of time steps until the first spike + t_spike_0 = theta_0 // bias + # Compute the following number of time steps until the second spike + # (according to `bias * (t_spike_0 + t_spike_refr) >= theta_0`) + t_spike_refr = theta_0 // bias - t_spike_0 + 1 + # Gold standard for the test + expected_spk_data = np.zeros((t_spike_0 + t_spike_refr + 1, shape[0])) + expected_spk_data[t_spike_0 - 1:t_spike_0 + t_spike_refr + 1: + t_spike_refr, :] = 1. + spk_data_through_run_needed = \ + spk_data_through_run[0:t_spike_0 + t_spike_refr + 1, :] + self.assertTrue(np.all(expected_spk_data + == spk_data_through_run_needed)) diff --git a/tests/lava/proc/atrlif/test_process.py b/tests/lava/proc/atrlif/test_process.py new file mode 100644 index 000000000..c0a16e94a --- /dev/null +++ b/tests/lava/proc/atrlif/test_process.py @@ -0,0 +1,43 @@ +# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024 Jannik Luboeinski +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import unittest +import numpy as np +from lava.proc.atrlif.process import ATRLIF + + +class TestATRLIFProcess(unittest.TestCase): + """Tests for ATRLIF class""" + def test_init(self): + """Tests instantiation of ATRLIF neuron""" + N = 100 + delta_i = 0.6 + delta_v = 0.6 + delta_theta = 0.4 + delta_r = 0.4 + theta_0 = 4 + theta_step = 2 + bias_mant = 2 * np.ones((N,), dtype=float) + bias_exp = np.ones((N,), dtype=float) + name = "ATRLIF" + + neur = ATRLIF(shape=(N,), + delta_i=delta_i, + delta_v=delta_v, + delta_theta=delta_theta, + delta_r=delta_r, + theta_0=theta_0, + theta=theta_0, + theta_step=theta_step, + bias_mant=bias_mant, + bias_exp=bias_exp, + name=name) + + self.assertEqual(neur.proc_params["shape"], (N,)) + self.assertEqual(neur.delta_i.init, delta_i) + self.assertEqual(neur.delta_v.init, delta_v) + self.assertListEqual(neur.bias_mant.init.tolist(), bias_mant.tolist()) + self.assertListEqual(neur.bias_exp.init.tolist(), bias_exp.tolist()) + self.assertEqual(neur.name, name) diff --git a/tests/lava/proc/conv_in_time/__init__.py b/tests/lava/proc/conv_in_time/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/lava/proc/conv_in_time/gts/q_weights.npy b/tests/lava/proc/conv_in_time/gts/q_weights.npy new file mode 100644 index 000000000..b061a7b57 --- /dev/null +++ b/tests/lava/proc/conv_in_time/gts/q_weights.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f78fb71a436122ae8bfccf4f0e13ce081758b5069029dc725c5291bef23f9872 +size 368 diff --git a/tests/lava/proc/conv_in_time/gts/spike_input.npy b/tests/lava/proc/conv_in_time/gts/spike_input.npy new file mode 100644 index 000000000..c67692abc --- /dev/null +++ b/tests/lava/proc/conv_in_time/gts/spike_input.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1121fc20bb641224327eaec7eb25719cd27a4186ad5b1afb307aadcf7778582 +size 288 diff --git a/tests/lava/proc/conv_in_time/gts/torch_output.npy b/tests/lava/proc/conv_in_time/gts/torch_output.npy new file mode 100644 index 000000000..1d108c072 --- /dev/null +++ b/tests/lava/proc/conv_in_time/gts/torch_output.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8de545175d4d511091d54b13cf0b1ed82b97104591d8b89596dd2a3069a509c4 +size 288 diff --git a/tests/lava/proc/conv_in_time/test_process.py b/tests/lava/proc/conv_in_time/test_process.py new file mode 100644 index 000000000..33ec3ca70 --- /dev/null +++ b/tests/lava/proc/conv_in_time/test_process.py @@ -0,0 +1,80 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import unittest +import os +import numpy as np +from lava.proc.conv_in_time.process import ConvInTime +from lava.proc import io + +from lava.magma.core.run_conditions import RunSteps +from lava.magma.core.run_configs import Loihi1SimCfg +from lava.proc.conv import utils + +if utils.TORCH_IS_AVAILABLE: + import torch + import torch.nn as nn + compare = True + # In this case, the test compares against random torch ground truth +else: + compare = False + # In this case, the test compares against saved torch ground truth + + +class TestConvInTimeProcess(unittest.TestCase): + """Tests for Conv class""" + def test_init(self) -> None: + """Tests instantiation of Conv In Time""" + num_steps = 10 + kernel_size = 3 + n_in = 2 + n_out = 5 + if compare: + spike_input = np.random.choice( + [0, 1], + size=(n_in, num_steps)) + weights = np.random.randint(256, size=[kernel_size, + n_out, + n_in]) - 128 + else: + spike_input = np.load(os.path.join(os.path.dirname(__file__), + "gts/spike_input.npy")) + weights = np.load(os.path.join(os.path.dirname(__file__), + "gts/q_weights.npy")) + sender = io.source.RingBuffer(data=spike_input) + conv_in_time = ConvInTime(weights=weights, name='conv_in_time') + + receiver = io.sink.RingBuffer( + shape=(n_out,), + buffer=num_steps + 1) + + sender.s_out.connect(conv_in_time.s_in) + conv_in_time.a_out.connect(receiver.a_in) + + run_condition = RunSteps(num_steps=num_steps + 1) + run_cfg = Loihi1SimCfg(select_tag="floating_pt") + + conv_in_time.run(condition=run_condition, run_cfg=run_cfg) + output = receiver.data.get() + conv_in_time.stop() + + if compare: + tensor_input = torch.tensor(spike_input, dtype=torch.float32) + tensor_weights = torch.tensor(weights, dtype=torch.float32) + conv_layer = nn.Conv1d( + in_channels=n_in, + out_channels=n_out, + kernel_size=kernel_size, bias=False) + # Permute the weights to match the torch format + conv_layer.weight = nn.Parameter(tensor_weights.permute(1, 2, 0)) + torch_output = conv_layer( + tensor_input.unsqueeze(0)).squeeze(0).detach().numpy() + else: + torch_output = np.load(os.path.join(os.path.dirname(__file__), + "gts/torch_output.npy")) + + self.assertEqual(output.shape, (n_out, num_steps + 1)) + # After kernel_size timesteps, + # the output should be the same as the torch output + assert np.allclose(output[:, kernel_size:], torch_output) diff --git a/tests/lava/proc/graded/test_graded.py b/tests/lava/proc/graded/test_graded.py index b4c4b5027..3c65b6087 100644 --- a/tests/lava/proc/graded/test_graded.py +++ b/tests/lava/proc/graded/test_graded.py @@ -6,7 +6,8 @@ import numpy as np from scipy.sparse import csr_matrix -from lava.proc.graded.process import GradedVec, NormVecDelay, InvSqrt +from lava.proc.graded.process import (GradedVec, GradedReluVec, + NormVecDelay, InvSqrt) from lava.proc.graded.models import inv_sqrt from lava.proc.dense.process import Dense from lava.proc.sparse.process import Sparse @@ -17,10 +18,10 @@ class TestGradedVecProc(unittest.TestCase): - """Tests for GradedVec""" + """Tests for GradedVec.""" def test_gradedvec_dot_dense(self): - """Tests that GradedVec and Dense computes dot product""" + """Tests that GradedVec and Dense computes dot product.""" num_steps = 10 v_thresh = 1 @@ -59,7 +60,7 @@ def test_gradedvec_dot_dense(self): self.assertTrue(np.all(out_data[:, (3, 7)] == expected_out[:, (2, 6)])) def test_gradedvec_dot_sparse(self): - """Tests that GradedVec and Dense computes dot product""" + """Tests that GradedVec and Sparse computes dot product""" num_steps = 10 v_thresh = 1 @@ -99,12 +100,97 @@ def test_gradedvec_dot_sparse(self): self.assertTrue(np.all(out_data[:, (3, 7)] == expected_out[:, (2, 6)])) +class TestGradedReluVecProc(unittest.TestCase): + """Tests for GradedReluVec""" + + def test_gradedreluvec_dot_dense(self): + """Tests that GradedReluVec and Dense computes dot product""" + num_steps = 10 + v_thresh = 1 + + weights1 = np.zeros((10, 1)) + weights1[:, 0] = (np.arange(10) - 5) * 0.2 + + inp_data = np.zeros((weights1.shape[1], num_steps)) + inp_data[:, 2] = 1000 + inp_data[:, 6] = 20000 + + weight_exp = 7 + weights1 *= 2**weight_exp + weights1 = weights1.astype('int') + + dense1 = Dense(weights=weights1, num_message_bits=24, + weight_exp=-weight_exp) + vec1 = GradedReluVec(shape=(weights1.shape[0],), + vth=v_thresh) + + generator = io.source.RingBuffer(data=inp_data) + logger = io.sink.RingBuffer(shape=(weights1.shape[0],), + buffer=num_steps) + + generator.s_out.connect(dense1.s_in) + dense1.a_out.connect(vec1.a_in) + vec1.s_out.connect(logger.a_in) + + vec1.run(condition=RunSteps(num_steps=num_steps), + run_cfg=Loihi2SimCfg(select_tag='fixed_pt')) + out_data = logger.data.get().astype('int') + vec1.stop() + + ww = np.floor(weights1 / 2) * 2 + expected_out = np.floor((ww @ inp_data) / 2**weight_exp) + expected_out *= expected_out > v_thresh + + self.assertTrue(np.all(out_data[:, (3, 7)] == expected_out[:, (2, 6)])) + + def test_gradedreluvec_dot_sparse(self): + """Tests that GradedReluVec and Sparse computes dot product""" + num_steps = 10 + v_thresh = 1 + + weights1 = np.zeros((10, 1)) + weights1[:, 0] = (np.arange(10) - 5) * 0.2 + + inp_data = np.zeros((weights1.shape[1], num_steps)) + inp_data[:, 2] = 1000 + inp_data[:, 6] = 20000 + + weight_exp = 7 + weights1 *= 2**weight_exp + weights1 = weights1.astype('int') + + sparse1 = Sparse(weights=csr_matrix(weights1), + num_message_bits=24, + weight_exp=-weight_exp) + vec1 = GradedReluVec(shape=(weights1.shape[0],), + vth=v_thresh) + + generator = io.source.RingBuffer(data=inp_data) + logger = io.sink.RingBuffer(shape=(weights1.shape[0],), + buffer=num_steps) + + generator.s_out.connect(sparse1.s_in) + sparse1.a_out.connect(vec1.a_in) + vec1.s_out.connect(logger.a_in) + + vec1.run(condition=RunSteps(num_steps=num_steps), + run_cfg=Loihi2SimCfg(select_tag='fixed_pt')) + out_data = logger.data.get().astype('int') + vec1.stop() + + ww = np.floor(weights1 / 2) * 2 + expected_out = np.floor((ww @ inp_data) / 2**weight_exp) + expected_out *= expected_out > v_thresh + + self.assertTrue(np.all(out_data[:, (3, 7)] == expected_out[:, (2, 6)])) + + class TestInvSqrtProc(unittest.TestCase): """Tests for inverse square process.""" def test_invsqrt_calc(self): - """Checks the InvSqrt calculation""" - fp_base = 12 # base of the decimal point + """Checks the InvSqrt calculation.""" + fp_base = 12 # Base of the decimal point num_steps = 25 weights1 = np.zeros((1, 1)) @@ -147,10 +233,10 @@ def test_invsqrt_calc(self): class TestNormVecDelayProc(unittest.TestCase): - """Tests for NormVecDelay""" + """Tests for NormVecDelay.""" def test_norm_vec_delay_out1(self): - """Checks the first channel output of NormVecDelay""" + """Checks the first channel output of NormVecDelay.""" weight_exp = 7 num_steps = 10 @@ -203,17 +289,19 @@ def test_norm_vec_delay_out1(self): ch1 = (weights1 @ inp_data1) / 2**weight_exp ch2 = (weights2 @ inp_data2) / 2**weight_exp - # I'm using roll to account for the two step delay but hacky - # be careful if inputs change - # hmm.. there seems to be a delay step missing compared to + # I'm using roll to account for the two step delay in NormVecDelay. + # However, this is a hack, as the inputs need to be 0 at the end + # of the simulation, since roll wraps the values. + # Be wary that this potentially won't be correct with different inputs. + # There seems to be a delay step missing compared to # ncmodel, not sure where the delay should go... expected_out = np.roll(ch1, 1) * ch2 - # Then there is one extra timestep from hardware + # Then there is one extra delay timestep from hardware self.assertTrue(np.all(expected_out[:, :-1] == out_data[:, 1:])) def test_norm_vec_delay_out2(self): - """Checks the second channel output of NormVecDelay""" + """Checks the second channel output of NormVecDelay.""" weight_exp = 7 num_steps = 10 @@ -265,7 +353,7 @@ def test_norm_vec_delay_out2(self): ch1 = (weights1 @ inp_data1) / 2**weight_exp expected_out = ch1 ** 2 - # then there is one extra timestep from hardware + # Then there is one extra timestep from hardware self.assertTrue(np.all(expected_out[:, :-1] == out_data[:, 1:])) diff --git a/tests/lava/proc/io/test_extractor.py b/tests/lava/proc/io/test_extractor.py index d918c1e10..ed73ed902 100644 --- a/tests/lava/proc/io/test_extractor.py +++ b/tests/lava/proc/io/test_extractor.py @@ -61,9 +61,9 @@ def run_spk(self) -> None: class TestExtractor(unittest.TestCase): def test_init(self): """Test that the Extractor Process is instantiated correctly.""" - in_shape = (1,) + shape = (1,) - extractor = Extractor(shape=in_shape) + extractor = Extractor(shape=shape) self.assertIsInstance(extractor, Extractor) @@ -73,11 +73,10 @@ def test_init(self): self.assertEqual(config.receive_empty, utils.ReceiveEmpty.BLOCKING) self.assertEqual(config.receive_not_empty, utils.ReceiveNotEmpty.FIFO) - self.assertIsInstance(extractor.proc_params["pm_to_p_src_port"], - CspSendPort) - self.assertIsInstance(extractor.in_port, InPort) - self.assertEqual(extractor.in_port.shape, in_shape) + self.assertEqual(extractor.in_port.shape, shape) + self.assertIsInstance(extractor.out_port, OutPort) + self.assertEqual(extractor.out_port.shape, shape) def test_invalid_shape(self): """Test that instantiating the Extractor Process with an invalid @@ -142,20 +141,8 @@ class TestPyLoihiExtractorModel(unittest.TestCase): def test_init(self): """Test that the PyLoihiExtractorModel ProcessModel is instantiated correctly.""" - shape = (1, ) - buffer_size = 10 - multi_processing = MultiProcessing() - multi_processing.start() - channel = PyPyChannel(message_infrastructure=multi_processing, - src_name="src", - dst_name="dst", - shape=shape, - dtype=float, - size=buffer_size) - - proc_params = {"channel_config": utils.ChannelConfig(), - "pm_to_p_src_port": channel.src_port} + proc_params = {"channel_config": utils.ChannelConfig()} pm = PyLoihiExtractorModel(proc_params) @@ -295,6 +282,8 @@ def test_receive_data_receive_empty_blocking(self): run_condition = RunSteps(num_steps=num_steps) run_cfg = Loihi2SimCfg() + ex = extractor.compile(run_cfg=run_cfg) + extractor.create_runtime(run_cfg=run_cfg, executable=ex) shared_queue = Queue(2) @@ -345,7 +334,14 @@ def test_receive_data_receive_empty_non_blocking_zeros(self): extractor = Extractor(shape=data_shape, buffer_size=buffer_size, channel_config=channel_config) + run_cfg = Loihi2SimCfg() + run_condition = RunSteps(num_steps=1) + ex = extractor.compile(run_cfg=run_cfg) + extractor.create_runtime(run_cfg=run_cfg, executable=ex) + recv_data = extractor.receive() + extractor.run(condition=run_condition) + extractor.stop() np.testing.assert_equal(recv_data, np.zeros(data_shape)) @@ -440,6 +436,8 @@ def test_run_steps_blocking(self): run_condition = RunSteps(num_steps=num_steps) run_cfg = Loihi2SimCfg() + ex = extractor.compile(run_cfg=run_cfg) + extractor.create_runtime(run_cfg=run_cfg, executable=ex) shared_queue = Queue(num_steps) @@ -532,9 +530,6 @@ def test_init(self): self.assertEqual(config.receive_empty, utils.ReceiveEmpty.BLOCKING) self.assertEqual(config.receive_not_empty, utils.ReceiveNotEmpty.FIFO) - self.assertIsInstance(listener.proc_params["pm_to_p_src_port"], - CspSendPort) - self.assertIsInstance(listener.wire_tap, RefPort) self.assertEqual(listener.wire_tap.shape, lif.u.shape) diff --git a/tests/lava/proc/io/test_injector.py b/tests/lava/proc/io/test_injector.py index a200d705d..df999bb59 100644 --- a/tests/lava/proc/io/test_injector.py +++ b/tests/lava/proc/io/test_injector.py @@ -79,9 +79,6 @@ def test_init(self): self.assertEqual(config.receive_empty, utils.ReceiveEmpty.BLOCKING) self.assertEqual(config.receive_not_empty, utils.ReceiveNotEmpty.FIFO) - self.assertIsInstance(injector.proc_params["p_to_pm_dst_port"], - CspRecvPort) - self.assertIsInstance(injector.out_port, OutPort) self.assertEqual(injector.out_port.shape, out_shape) @@ -212,6 +209,8 @@ def _test_send_full_policy(send_full: utils.SendFull) \ run_condition = RunSteps(num_steps=num_steps) run_cfg = Loihi2SimCfg() + ex = injector.compile(run_cfg=run_cfg) + injector.create_runtime(run_cfg=run_cfg, executable=ex) shared_queue = Queue(2) @@ -299,6 +298,8 @@ def test_send_data_receive_empty_blocking(self): run_condition = RunSteps(num_steps=num_steps) run_cfg = Loihi2SimCfg() + ex = injector.compile(run_cfg=run_cfg) + injector.create_runtime(run_cfg=run_cfg, executable=ex) injector.send(np.ones(data_shape)) injector.run(condition=run_condition, run_cfg=run_cfg) @@ -405,6 +406,8 @@ def _test_receive_not_empty_policy(receive_not_empty: utils.ReceiveNotEmpty, run_condition = RunSteps(num_steps=num_steps) run_cfg = Loihi2SimCfg() + ex = injector.compile(run_cfg=run_cfg) + injector.create_runtime(run_cfg=run_cfg, executable=ex) injector.send(send_data[0]) injector.send(send_data[1]) @@ -457,6 +460,8 @@ def test_run_steps_blocking(self): run_condition = RunSteps(num_steps=num_steps) run_cfg = Loihi2SimCfg() + ex = injector.compile(run_cfg=run_cfg) + injector.create_runtime(run_cfg=run_cfg, executable=ex) def thread_2_fn() -> None: for send_data_single_item in data: @@ -468,6 +473,7 @@ def thread_2_fn() -> None: injector.run(condition=run_condition, run_cfg=run_cfg) recv_var_data = recv.var.get() injector.stop() + thread_2.join() np.testing.assert_equal(recv_var_data, data) diff --git a/tests/lava/proc/lif/test_models.py b/tests/lava/proc/lif/test_models.py index d9ec66528..1d9f29943 100644 --- a/tests/lava/proc/lif/test_models.py +++ b/tests/lava/proc/lif/test_models.py @@ -837,12 +837,13 @@ def test_float_model(self): refractory_period = 1 # Two neurons with different biases + # No Input current provided to make the voltage dependent on the bias lif_refractory = LIFRefractory(shape=(num_neurons,), - u=np.arange(num_neurons), + u=np.zeros(num_neurons), bias_mant=np.arange(num_neurons) + 1, bias_exp=np.ones( (num_neurons,), dtype=float), - vth=4., + vth=4, refractory_period=refractory_period) v_logger = io.sink.Read(buffer=num_steps) @@ -856,6 +857,6 @@ def test_float_model(self): # Voltage is expected to remain at reset level for two time steps v_expected = np.array([[1, 2, 3, 4, 0, 0, 1, 2], - [2, 0, 0, 2, 0, 0, 2, 0]], dtype=float) + [2, 4, 0, 0, 2, 4, 0, 0]], dtype=float) assert_almost_equal(v, v_expected) diff --git a/tests/lava/proc/prodneuron/test_prod_neuron.py b/tests/lava/proc/prodneuron/test_prod_neuron.py index 13919d3b9..65eb2bf2e 100644 --- a/tests/lava/proc/prodneuron/test_prod_neuron.py +++ b/tests/lava/proc/prodneuron/test_prod_neuron.py @@ -14,7 +14,10 @@ class TestProdNeuronProc(unittest.TestCase): + """Tests for ProdNeuron.""" + def test_prod_neuron_out(self): + """Tests prod neuron calcultion is correct.""" weight_exp = 7 num_steps = 10 @@ -68,7 +71,7 @@ def test_prod_neuron_out(self): ch2 = (weights2 @ inp_data2) / 2**weight_exp expected_out = ch1 * ch2 - # then there is one extra timestep from hardware + # Then there is one extra timestep from hardware self.assertTrue(np.all(expected_out[:, :-1] == out_data[:, 1:])) diff --git a/tests/lava/proc/s4d/dA_complex.npy b/tests/lava/proc/s4d/dA_complex.npy new file mode 100644 index 000000000..1d61ccc37 --- /dev/null +++ b/tests/lava/proc/s4d/dA_complex.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:342546700242502415e6c81e2b620c915250f56447b7d46eb56feec9e0bb1629 +size 80128 diff --git a/tests/lava/proc/s4d/dB_complex.npy b/tests/lava/proc/s4d/dB_complex.npy new file mode 100644 index 000000000..e5c858679 --- /dev/null +++ b/tests/lava/proc/s4d/dB_complex.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1195dc519e74ffe535918b6112a080e7b0458d61189c9a8e51cf3ea30edd8ec9 +size 80128 diff --git a/tests/lava/proc/s4d/dC_complex.npy b/tests/lava/proc/s4d/dC_complex.npy new file mode 100644 index 000000000..185cb40fa --- /dev/null +++ b/tests/lava/proc/s4d/dC_complex.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7db2dbb793555e0836e557db355d2f6861b32a92b431443bf4c102e4626bf473 +size 80128 diff --git a/tests/lava/proc/s4d/s4d_A.dat.npy b/tests/lava/proc/s4d/s4d_A.dat.npy new file mode 100644 index 000000000..081fdd6ec --- /dev/null +++ b/tests/lava/proc/s4d/s4d_A.dat.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e4c9f5f11d3139b86ccdfe3d8e2179566dc8ac8da31a4a23951dba174425663 +size 5248 diff --git a/tests/lava/proc/s4d/s4d_B.dat.npy b/tests/lava/proc/s4d/s4d_B.dat.npy new file mode 100644 index 000000000..916b75ffb --- /dev/null +++ b/tests/lava/proc/s4d/s4d_B.dat.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b67f99c0a172c862abfc65b3aabeba9bc91fe1f2254d0df066d19c9b3e3b8fe +size 5248 diff --git a/tests/lava/proc/s4d/s4d_C.dat.npy b/tests/lava/proc/s4d/s4d_C.dat.npy new file mode 100644 index 000000000..910f44a96 --- /dev/null +++ b/tests/lava/proc/s4d/s4d_C.dat.npy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:055720b65a2eb0bf0043989b1a078cc028f7a105a0cb394ba03cdbf3adac8ac1 +size 5248 diff --git a/tests/lava/proc/s4d/test_models.py b/tests/lava/proc/s4d/test_models.py new file mode 100644 index 000000000..64fe33da8 --- /dev/null +++ b/tests/lava/proc/s4d/test_models.py @@ -0,0 +1,281 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + + +import unittest +import numpy as np +from typing import Tuple +import lava.proc.io as io +from lava.magma.core.run_conditions import RunSteps +from lava.proc.sdn.process import ActivationMode, SigmaDelta +from lava.proc.s4d.process import S4d, SigmaS4dDelta, SigmaS4dDeltaLayer +from lava.proc.sparse.process import Sparse +from lava.magma.core.run_configs import Loihi2SimCfg +from tests.lava.proc.s4d.utils import get_coefficients, run_original_model + + +class TestS4DModel(unittest.TestCase): + """Tests for S4d neuron""" + def run_in_sim( + self, + inp: np.ndarray, + a: np.ndarray, + b: np.ndarray, + c: np.ndarray, + num_steps: int, + model_dim: int, + d_states: int, + ) -> Tuple[np.ndarray]: + + # Get S4D matrices + a = a[:model_dim * d_states] + b = b[:model_dim * d_states] + c = c[:model_dim * d_states] + + # Setup network: input -> expansion -> S4D neuron -> output + kron_matrix = np.kron(np.eye(model_dim), np.ones((d_states, ))) + spiker = io.source.RingBuffer(data=inp) + sparse_1 = Sparse(weights=kron_matrix.T, num_message_bits=24) + neuron = S4d(shape=((model_dim * d_states,)), + a=a, + b=b, + c=c) + + receiver = io.sink.RingBuffer(buffer=num_steps, + shape=(model_dim * d_states,)) + spiker.s_out.connect(sparse_1.s_in) + sparse_1.a_out.connect(neuron.a_in) + neuron.s_out.connect(receiver.a_in) + + run_cfg = Loihi2SimCfg(select_tag="floating_pt") + neuron.run( + condition=RunSteps(num_steps=num_steps), run_cfg=run_cfg) + received_data_sim = receiver.data.get() + neuron.stop() + + return received_data_sim + + def compare_s4d_model_to_original_equations(self, + model_dim: int = 10, + d_states: int = 5, + n_steps: int = 5, + inp_exp: int = 5, + is_real: bool = False) -> None: + + """Asserts that the floating point lava simulation for S4d outputs + exactly the same values as the original equations.""" + a, b, c = get_coefficients(is_real=is_real) + np.random.seed(0) + inp = (np.random.random((model_dim, n_steps)) * 2**inp_exp).astype(int) + out_lava = self.run_in_sim(inp=inp, + num_steps=n_steps, + a=a, + b=b, + c=c, + model_dim=model_dim, + d_states=d_states) + out_original_equations = run_original_model(inp=inp, + num_steps=n_steps, + model_dim=model_dim, + d_states=d_states, + a=a, + b=b, + c=c, + perform_reduction=False) + + np.testing.assert_array_equal(out_original_equations[:, :-1], + out_lava[:, 1:]) + + def test_s4d_real_model_single_hidden_state(self) -> None: + self.compare_s4d_model_to_original_equations(is_real=True, d_states=1) + + def test_s4d_real_model_multiple_hidden_state(self) -> None: + self.compare_s4d_model_to_original_equations(is_real=True, d_states=5) + + def test_s4d_complex_model_single_hidden_state(self) -> None: + self.compare_s4d_model_to_original_equations(is_real=False, d_states=1) + + def test_s4d_complex_model_multiple_hidden_state(self) -> None: + self.compare_s4d_model_to_original_equations(is_real=False, d_states=5) + + +class TestSigmaS4DDeltaModels(unittest.TestCase): + """Tests for SigmaS4Delta neuron""" + def run_in_lava( + self, + inp, + a: np.ndarray, + b: np.ndarray, + c: np.ndarray, + num_steps: int, + model_dim: int, + d_states: int, + use_layer: bool) -> Tuple[np.ndarray]: + + """ Run S4d model in lava. + + Parameters + ---------- + inp : np.ndarray + Input signal to the model. + num_steps : int + Number of time steps to simulate the model. + model_dim : int + Dimensionality of the model. + d_states : int + Number of model states. + use_layer : bool + Whether to use the layer implementation of the model + (SigmaS4DeltaLayer, helpful for multiple d_states) or just + the neuron model (SigmaS4Delta). + + Returns + ------- + Tuple[np.ndarray] + Tuple containing the output of the model simulation. + """ + + a = a[:model_dim * d_states] + b = b[:model_dim * d_states] + c = c[:model_dim * d_states] + + diff = inp[:, 1:] - inp[:, :-1] + diff = np.concatenate((inp[:, :1], diff), axis=1) + + spiker = io.source.RingBuffer(data=diff) + receiver = io.sink.RingBuffer(shape=(model_dim,), buffer=num_steps) + + if use_layer: + s4d_layer = SigmaS4dDeltaLayer(shape=(model_dim,), + d_states=d_states, + num_message_bits=24, + vth=0, + a=a, + b=b, + c=c) + buffer_neuron = SigmaDelta(shape=(model_dim,), + vth=0, + cum_error=True, + act_mode=ActivationMode.UNIT) + spiker.s_out.connect(s4d_layer.s_in) + s4d_layer.a_out.connect(buffer_neuron.a_in) + buffer_neuron.s_out.connect(receiver.a_in) + + else: + sparse = Sparse(weights=np.eye(model_dim), num_message_bits=24) + s4d_neuron = SigmaS4dDelta(shape=((model_dim,)), + vth=0, + a=a, + b=b, + c=c) + spiker.s_out.connect(sparse.s_in) + sparse.a_out.connect(s4d_neuron.a_in) + s4d_neuron.s_out.connect(receiver.a_in) + + run_condition = RunSteps(num_steps=num_steps) + run_config = Loihi2SimCfg() + + spiker.run(condition=run_condition, run_cfg=run_config) + output = receiver.data.get() + spiker.stop() + + output = np.cumsum(output, axis=1) + + return output + + def test_py_model_vs_original_equations(self) -> None: + """Tests that the pymodel for SigmaS4dDelta outputs approximately + the same values as the original S4D equations. + """ + a, b, c = get_coefficients() + model_dim = 3 + d_states = 1 + n_steps = 5 + np.random.seed(0) + inp = np.random.random((model_dim, n_steps)) * 2**6 + + out_chip = self.run_in_lava(inp=inp, + a=a, + b=b, + c=c, + num_steps=n_steps, + model_dim=model_dim, + d_states=d_states, + use_layer=False + ) + out_original_model = run_original_model(inp=inp, + model_dim=model_dim, + d_states=d_states, + num_steps=n_steps, + a=a, + b=b, + c=c) + + np.testing.assert_array_equal(out_original_model[:, :-1], + out_chip[:, 1:]) + + def test_py_model_layer_vs_original_equations(self) -> None: + """ Tests that the pymodel for SigmaS4DeltaLayer outputs approximately + the same values as the original S4D equations for multiple d_states. + """ + a, b, c = get_coefficients() + model_dim = 3 + d_states = 3 + n_steps = 5 + np.random.seed(1) + inp = np.random.random((model_dim, n_steps)) * 2**6 + + out_chip = self.run_in_lava(inp=inp, + a=a, + b=b, + c=c, + num_steps=n_steps, + model_dim=model_dim, + d_states=d_states, + use_layer=True, + ) + out_original_model = run_original_model(inp=inp, + model_dim=model_dim, + d_states=d_states, + num_steps=n_steps, + a=a, + b=b, + c=c) + + np.testing.assert_allclose(out_original_model[:, :-2], out_chip[:, 2:]) + + def test_py_model_vs_py_model_layer(self) -> None: + """Tests that the pymodel for SigmaS4DeltaLayer outputs approximately + the same values as just the SigmaS4DDelta Model with one hidden dim. + """ + a, b, c = get_coefficients() + model_dim = 3 + d_states = 1 + n_steps = 5 + np.random.seed(2) + inp = np.random.random((model_dim, n_steps)) * 2**6 + + out_just_model = self.run_in_lava(inp=inp, + a=a, + b=b, + c=c, + num_steps=n_steps, + model_dim=model_dim, + d_states=d_states, + use_layer=False) + + out_layer = self.run_in_lava(inp=inp, + a=a, + b=b, + c=c, + num_steps=n_steps, + model_dim=model_dim, + d_states=d_states, + use_layer=True) + + np.testing.assert_allclose(out_layer[:, 1:], out_just_model[:, :-1]) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/lava/proc/s4d/test_process.py b/tests/lava/proc/s4d/test_process.py new file mode 100644 index 000000000..cd6b5f2d3 --- /dev/null +++ b/tests/lava/proc/s4d/test_process.py @@ -0,0 +1,110 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import unittest +import numpy as np +from lava.proc.s4d.process import SigmaS4dDelta, SigmaS4dDeltaLayer, S4d + + +class TestS4dProcess(unittest.TestCase): + """Tests for S4d Class""" + + def test_init(self) -> None: + """Tests instantiation of S4d""" + shape = 10 + s4_exp = 12 + inp_exp = 8 + a = np.ones(shape) * 0.5 + b = np.ones(shape) * 0.8 + c = np.ones(shape) * 0.9 + s4d = S4d(shape=(shape,), + s4_exp=s4_exp, + inp_exp=inp_exp, + a=a, + b=b, + c=c) + + self.assertEqual(s4d.shape, (shape,)) + self.assertEqual(s4d.s4_exp.init, s4_exp) + self.assertEqual(s4d.inp_exp.init, inp_exp) + np.testing.assert_array_equal(s4d.a.init, a) + np.testing.assert_array_equal(s4d.b.init, b) + np.testing.assert_array_equal(s4d.c.init, c) + self.assertEqual(s4d.s4_state.init, 0) + + +class TestSigmaS4dDeltaProcess(unittest.TestCase): + """Tests for SigmaS4dDelta Class""" + + def test_init(self) -> None: + """Tests instantiation of SigmaS4dDelta""" + shape = 10 + vth = 10 + state_exp = 6 + s4_exp = 12 + a = np.ones(shape) * 0.5 + b = np.ones(shape) * 0.8 + c = np.ones(shape) * 0.9 + sigma_s4_delta = SigmaS4dDelta(shape=(shape,), + vth=vth, + state_exp=state_exp, + s4_exp=s4_exp, + a=a, + b=b, + c=c) + + # determined by user - S4 part + self.assertEqual(sigma_s4_delta.shape, (shape,)) + self.assertEqual(sigma_s4_delta .vth.init, vth * 2 ** state_exp) + self.assertEqual(sigma_s4_delta.s4_exp.init, s4_exp) + np.testing.assert_array_equal(sigma_s4_delta.a.init, a) + np.testing.assert_array_equal(sigma_s4_delta.b.init, b) + np.testing.assert_array_equal(sigma_s4_delta.c.init, c) + self.assertEqual(sigma_s4_delta.state_exp.init, state_exp) + self.assertEqual(sigma_s4_delta.s4_state.init, 0) + + # default sigma-delta params - inherited from SigmaDelta class + self.assertEqual(sigma_s4_delta.cum_error.init, False) + self.assertEqual(sigma_s4_delta.spike_exp.init, 0) + self.assertEqual(sigma_s4_delta.bias.init, 0) + + +class TestSigmaS4DeltaLayer(unittest.TestCase): + """Tests for SigmaS4dDeltaLayer Class""" + + def test_init(self) -> None: + """Tests instantiation of SigmaS4dDeltaLayer """ + shape = 10 + vth = 10 + state_exp = 6 + s4_exp = 12 + d_states = 5 + a = np.ones(shape) * 0.5 + b = np.ones(shape) * 0.8 + c = np.ones(shape) * 0.9 + + sigma_s4d_delta_layer = SigmaS4dDeltaLayer(shape=(shape,), + d_states=d_states, + vth=vth, + state_exp=state_exp, + s4_exp=s4_exp, + a=a, + b=b, + c=c) + # determined by user - S4 part + self.assertEqual(sigma_s4d_delta_layer.shape, (shape,)) + self.assertEqual(sigma_s4d_delta_layer.S4_exp.init, s4_exp) + np.testing.assert_array_equal(sigma_s4d_delta_layer.a.init, a) + np.testing.assert_array_equal(sigma_s4d_delta_layer.b.init, b) + np.testing.assert_array_equal(sigma_s4d_delta_layer.c.init, c) + self.assertEqual(sigma_s4d_delta_layer.state_exp.init, state_exp) + self.assertEqual(sigma_s4d_delta_layer.s4_state.init, 0) + + # determined by user/via number of states and shape + np.testing.assert_array_equal(sigma_s4d_delta_layer.conn_weights.init, + np.kron(np.eye(shape), np.ones(d_states))) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/lava/proc/s4d/utils.py b/tests/lava/proc/s4d/utils.py new file mode 100644 index 000000000..a323da338 --- /dev/null +++ b/tests/lava/proc/s4d/utils.py @@ -0,0 +1,96 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import os +import numpy as np +from typing import List, Tuple + + +def get_coefficients( + is_real: bool = True) -> [np.ndarray, np.ndarray, np.ndarray]: + curr_dir = os.path.dirname(os.path.realpath(__file__)) + + # Initialize A, B and C with values + if is_real: + s4d_A = np.load(curr_dir + "/s4d_A.dat.npy").flatten() + s4d_B = np.load(curr_dir + "/s4d_B.dat.npy").flatten() + s4d_C = np.load(curr_dir + "/s4d_C.dat.npy").flatten().flatten() + else: + s4d_A = np.load(curr_dir + "/dA_complex.npy").flatten() + s4d_B = np.load(curr_dir + "/dB_complex.npy").flatten() + s4d_C = np.load(curr_dir + "/dC_complex.npy").flatten().flatten() + + return s4d_A, s4d_B, s4d_C + + +def run_original_model( + inp: np.ndarray, + num_steps: int, + model_dim: int, + d_states: int, + a: np.ndarray, + b: np.ndarray, + c: np.ndarray, + perform_reduction: bool = True) -> Tuple[np.ndarray]: + """ + Run original S4d model in full precision. + + This function simulates the behavior of a linear time-invariant system + with diagonalized state-space representation. (S4D) + The state-space equations are given by: + s4_state_{k+1} = A * s4_state_k + B * input_k + out_k = C * s4_state_k + + where: + - s4_state_k is the state vector at time step k, + - input_k is the input vector at time step k, + - out_k is the output vector at time step k, + - A is the diagonal state matrix, + - B is the diagonal input matrix, + - C is the diagonal output matrix. + + The function computes the next output step of the + system for the given input signal. + + The function computes the output of the system for the given input signal + over num_steps time steps. + + Parameters + ---------- + inp: np.ndarray + Input signal to the model. + num_steps: int + Number of time steps to simulate the model. + model_dim: int + Dimensionality of the model. + d_states: int + Number of model states. + a: np.ndarray + Diagonal elements of the state matrix of the S4D model. + b: np.ndarray + Diagonal elements of the input matrix of the S4D model. + c: np.ndarray + Diagonal elements of the output matrix of the S4D model. + + Returns + ------- + Tuple[np.ndarray] + Tuple containing the output of the model simulation. + """ + + a = a[:model_dim * d_states] + b = b[:model_dim * d_states] + c = c[:model_dim * d_states] + expansion_weights = np.kron(np.eye(model_dim), np.ones(d_states)) + expanded_inp = np.matmul(expansion_weights.T, inp) + out = np.zeros((model_dim * d_states, num_steps)) + s4_state = np.zeros((model_dim * d_states,)).flatten() + + for idx, data_in in enumerate(expanded_inp.T): + s4_state = s4_state * a + data_in * b + out[:, idx] = np.real(c * s4_state * 2) + + if perform_reduction: + out = np.matmul(expansion_weights, out) + return out diff --git a/tests/lava/tutorials/test_tutorials-lva.py b/tests/lava/tutorials/test_tutorials-lva.py new file mode 100644 index 000000000..7234c5de4 --- /dev/null +++ b/tests/lava/tutorials/test_tutorials-lva.py @@ -0,0 +1,222 @@ +# Copyright (C) 2022-2024 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import glob +import os +import platform +import subprocess # noqa S404 +import sys +import tempfile +import typing as ty +import unittest +from test import support + +import lava +import nbformat + +import tutorials + + +class TestTutorials(unittest.TestCase): + """Export notebook, execute to check for errors.""" + + system_name = platform.system().lower() + + def _execute_notebook( + self, base_dir: str, path: str + ) -> ty.Tuple[ty.Type[nbformat.NotebookNode], ty.List[str]]: + """Execute a notebook via nbconvert and collect output. + + Parameters + ---------- + base_dir : str + notebook search directory + path : str + path to notebook + + Returns + ------- + Tuple + (parsed nbformat.NotebookNode object, list of execution errors) + """ + + cwd = os.getcwd() + dir_name, notebook = os.path.split(path) + try: + env = self._update_pythonpath(base_dir, dir_name) + nb = self._convert_and_execute_notebook(notebook, env) + errors = self._collect_errors_from_all_cells(nb) + except Exception as e: + nb = None + errors = str(e) + finally: + os.chdir(cwd) + + return nb, errors + + def _update_pythonpath( + self, base_dir: str, dir_name: str + ) -> ty.Dict[str, str]: + """Update PYTHONPATH with notebook location. + + Parameters + ---------- + base_dir : str + Parent directory to use + dir_name : str + Directory containing notebook + + Returns + ------- + env : dict + Updated dictionary of environment variables + """ + os.chdir(base_dir + "/" + dir_name) + + env = os.environ.copy() + module_path = [lava.__path__.__dict__["_path"][0]] + + module_path.extend( + [os.path.dirname(module_path[0]), env.get("PYTHONPATH", "")] + ) + + sys_path = ":".join(map(str, sys.path)) + env_path = env.get("PYTHONPATH", "") + mod_path = ":".join(map(str, module_path)) + + env["PYTHONPATH"] = env_path + ":" + mod_path + ":" + sys_path + + return env + + def _convert_and_execute_notebook( + self, notebook: str, env: ty.Dict[str, str] + ) -> ty.Type[nbformat.NotebookNode]: + """Covert notebook and execute it. + + Parameters + ---------- + notebook : str + Notebook name + env : dict + Dictionary of environment variables + + Returns + ------- + nb : nbformat.NotebookNode + Notebook dict-like node with attribute-access + """ + with tempfile.NamedTemporaryFile(mode="w+t", suffix=".ipynb") as fout: + args = [ + "jupyter", + "nbconvert", + "--to", + "notebook", + "--execute", + "--ExecutePreprocessor.timeout=-1", + "--output", + fout.name, + notebook, + ] + subprocess.check_call(args, env=env) # nosec # noqa: S603 + + fout.seek(0) + return nbformat.read(fout, nbformat.current_nbformat) + + def _collect_errors_from_all_cells( + self, nb: nbformat.NotebookNode + ) -> ty.List[str]: + """Collect errors from executed notebook. + + Parameters + ---------- + nb : nbformat.NotebookNode + Notebook to search for errors + + Returns + ------- + List + Collection of errors + """ + errors = [] + for cell in nb.cells: + if "outputs" in cell: + for output in cell["outputs"]: + if output.output_type == "error": + errors.append(output) + return errors + + def _run_notebook(self, notebook: str): + """Run a specific notebook + + Parameters + ---------- + notebook : str + name of notebook to run + """ + cwd = os.getcwd() + tutorials_temp_directory = tutorials.__path__.__dict__["_path"][0] + tutorials_directory = "" + + tutorials_directory = os.path.realpath(tutorials_temp_directory) + os.chdir(tutorials_directory) + + errors_record = {} + + try: + glob_pattern = "**/{}".format(notebook) + discovered_notebooks = sorted( + glob.glob(glob_pattern, recursive=True) + ) + + self.assertTrue( + len(discovered_notebooks) != 0, + "Notebook not found. Input to function {}".format(notebook), + ) + + # If the notebook is found execute it and store any errors + for notebook_name in discovered_notebooks: + nb, errors = self._execute_notebook( + str(tutorials_directory), notebook_name + ) + errors_joined = ( + "\n".join(errors) if isinstance(errors, list) else errors + ) + if errors: + errors_record[notebook_name] = (errors_joined, nb) + + self.assertFalse( + errors_record, + "Failed to execute Jupyter Notebooks \ + with errors: \n {}".format( + errors_record + ), + ) + finally: + os.chdir(cwd) + + @unittest.skipIf(system_name != "linux", "Tests work on linux") + def test_lava_va_01(self): + """Test tutorial lava va 01, Fixed point dot product.""" + self._run_notebook("lava_va/Tutorial01-Fixed_point_dot_product.ipynb") + + @unittest.skipIf(system_name != "linux", "Tests work on linux") + def test_lava_va_02(self): + """Test tutorial lava va 02, Fixed point element-wise product.""" + self._run_notebook( + "lava_va/" + + "Tutorial02-Fixed_point_elementwise_product.ipynb") + + @unittest.skipIf(system_name != "linux", "Tests work on linux") + def test_lava_va_03(self): + """Test tutorial lava va 03, Normalization Network.""" + self._run_notebook("lava_va/Tutorial03-Normalization_network.ipynb") + + @unittest.skipIf(system_name != "linux", "Tests work on linux") + def test_lava_va_04(self): + """Test tutorial lava va 04, Creating network motifs.""" + self._run_notebook("lava_va/Tutorial04-Creating_network_motifs.ipynb") + + +if __name__ == "__main__": + support.run_unittest(TestTutorials) diff --git a/tests/lava/tutorials/test_tutorials.py b/tests/lava/tutorials/test_tutorials.py index 3f752c081..53996e692 100644 --- a/tests/lava/tutorials/test_tutorials.py +++ b/tests/lava/tutorials/test_tutorials.py @@ -1,4 +1,5 @@ -# Copyright (C) 2022 Intel Corporation +# Copyright (C) 2022-2024 Intel Corporation +# Copyright (C) 2024 Jannik Luboeinski # SPDX-License-Identifier: BSD-3-Clause # See: https://spdx.org/licenses/ @@ -285,6 +286,11 @@ def test_in_depth_11_serialization(self): """Test tutorial serialization.""" self._run_notebook("tutorial11_serialization.ipynb") + @unittest.skipIf(system_name != "linux", "Tests work on linux") + def test_in_depth_12_adaptive_neurons(self): + """Test tutorial adaptive_neurons.""" + self._run_notebook("tutorial12_adaptive_neurons.ipynb") + @unittest.skipIf(system_name != "linux", "Tests work on linux") def test_in_depth_clp_01(self): """Test tutorial CLP 01.""" diff --git a/tutorials/in_depth/tutorial12_adaptive_neurons.ipynb b/tutorials/in_depth/tutorial12_adaptive_neurons.ipynb new file mode 100644 index 000000000..6dc80a662 --- /dev/null +++ b/tutorials/in_depth/tutorial12_adaptive_neurons.ipynb @@ -0,0 +1,329 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Copyright (C) 2024 Jannik Luboeinski*
\n", + "*SPDX-License-Identifier: BSD-3-Clause*
\n", + "*See: https://spdx.org/licenses/*\n", + "\n", + "---\n", + "\n", + "# ATRLIF neuron in different implementations\n", + "_A Leaky Integrate-and-Fire neuron with adaptive threshold and adaptive refractoriness._" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# Import general modules\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import os\n", + "\n", + "# Import Lava core modules\n", + "from lava.magma.core.run_configs import Loihi2SimCfg, Loihi2HwCfg\n", + "from lava.magma.core.run_conditions import RunSteps\n", + "\n", + "# Import Lava monitors\n", + "from lava.proc.monitor.process import Monitor\n", + "\n", + "# Import ATRLIF process\n", + "from lava.proc.atrlif.process import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Simulation test function" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def simulation_test(run_config, label, bias_mant=3, bias_exp=0, **kwargs):\n", + " '''\n", + " Function to simulate and monitor a population of ATRLIF neurons.\n", + " \n", + " Parameters\n", + " ----------\n", + " run_config : `AbstractLoihiSimRunCfg`\n", + " Run configuratrion object for Lava.\n", + " label : `str`\n", + " Label for the current simulation.\n", + " bias_mant : `float`, optional\n", + " Mantissa part of neuron's bias. Equals `bias` for floating-point implementation.\n", + " bias_exp : `int`, optional\n", + " Exponent part of neuron's bias, if needed. Ignored in floating-point implementation.\n", + " **kwargs : `dict`\n", + " Additional keyword arguments (cf. 'atrlif_process.py').\n", + " '''\n", + "\n", + " # Initialization\n", + " n_neurons = 1 # the number of neurons\n", + " num_steps = 20 # the number of timesteps\n", + " output_period = 1 # the sampling period (in timesteps)\n", + " num_samples = num_steps // output_period + 1 # the number of samples\n", + " atrlif = ATRLIF(shape=(n_neurons,), bias_mant=bias_mant, bias_exp=bias_exp, **kwargs)\n", + " \n", + " # Set monitors for the different variables\n", + " voltage_mon = Monitor()\n", + " voltage_mon.probe(atrlif.v, num_samples)\n", + " refractory_mon = Monitor()\n", + " refractory_mon.probe(atrlif.r, num_samples)\n", + " threshold_mon = Monitor()\n", + " threshold_mon.probe(atrlif.theta, num_samples)\n", + " spike_mon = Monitor()\n", + " spike_mon.probe(atrlif.s_out, num_samples)\n", + " \n", + " # Run the simulation\n", + " atrlif.run(condition=RunSteps(num_steps=num_samples, blocking=True), run_cfg=run_config)\n", + " \n", + " # Retrieve process name\n", + " process_name = atrlif.v.process.name\n", + " \n", + " # Collect samples\n", + " data_v = voltage_mon.get_data()[process_name]['v']\n", + " data_r = refractory_mon.get_data()[process_name]['r']\n", + " data_theta = threshold_mon.get_data()[process_name]['theta']\n", + " data_s = spike_mon.get_data()[process_name]['s_out']\n", + " \n", + " # Stop the simulation\n", + " atrlif.stop()\n", + " \n", + " # Normalize data from fixed-point implementation (right shifting by `bias_exp`)\n", + " if bias_exp > 0:\n", + " data_v = data_v * 2**(-bias_exp)\n", + " data_r = data_r * 2**(-bias_exp)\n", + " data_theta = data_theta * 2**(-bias_exp)\n", + " \n", + " # Save voltage and spike data\n", + " header = \"t\"\n", + " for var in [\"v\", \"r\", \"theta\", \"s\"]:\n", + " for n in range(n_neurons):\n", + " header += f\"\\t{var}_{n}\"\n", + " times = np.arange(0, len(data_v))\n", + " os.makedirs(\"./results\", exist_ok=True)\n", + " np.savetxt(f\"./results/atrlif_v_{label}.txt\",\n", + " np.column_stack([times, data_v, data_r, data_theta, data_s]), \n", + " fmt=\"%.0f\"+n_neurons*\"\\t%.4f\\t%.4f\\t%.4f\"+n_neurons*\"\\t%.0f\", \n", + " header=header)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plotting function" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def plot(data_stacked_1, data_stacked_2, framework_name_1, framework_name_2, X_cols, store_path = \"figure.svg\"):\n", + " '''\n", + " Function to plot the results from two different paradigms.\n", + " Based on https://github.com/jlubo/memory-consolidation-stc/blob/main/analysis/plotSimResultsComparisonMeanSEM.py.\n", + " \n", + " Parameters\n", + " ----------\n", + " data_stacked_1 : `numpy.ndarray`\n", + " Data array of first paradigm. First column contains the time, the other columns contain the data specified via `X_cols`.\n", + " data_stacked_2 : `numpy.ndarray`\n", + " Data array of second paradigm. First column contains the time, the other columns contain the data specified via `X_cols`.\n", + " framework_name_1 : `str`\n", + " Name of the first framework/paradigm.\n", + " framework_name_2 : `str`\n", + " Name of the second framework/paradigm.\n", + " X_cols : `dict` of `int`\n", + " Dictionary specifying the data columns to be plotted.\n", + " store_path : `str`, optional\n", + " Path to store the resulting graphics file.\n", + " '''\n", + " \n", + " # Figure setting\n", + " fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True, figsize=(8, 8), height_ratios=[1.0, 0.4])\n", + " \n", + " # Plot membrane voltage, effective voltage, and threshold dynamics\n", + " axes[0].set_ylabel(f\"Membrane dynamics (mV)\")\n", + " axes[0].plot(data_stacked_1[:,0], data_stacked_1[:,X_cols[\"theta\"]], color=\"#aaeeaa\", label=f\"Threshold {framework_name_1}\", marker='None', zorder=9)\n", + " axes[0].plot(data_stacked_2[:,0], data_stacked_2[:,X_cols[\"theta\"]], color=\"#556655\", linestyle='dotted', label=f\"Threshold {framework_name_2}\", marker='None', zorder=10)\n", + " axes[0].legend()\n", + " axes[0].plot(data_stacked_1[:,0], (data_stacked_1[:,X_cols[\"voltage\"]]-data_stacked_1[:,X_cols[\"ref\"]]), color=\"#ff0000\", label=f\"Effective voltage {framework_name_1}\", marker='None', zorder=9)\n", + " axes[0].plot(data_stacked_2[:,0], (data_stacked_2[:,X_cols[\"voltage\"]]-data_stacked_2[:,X_cols[\"ref\"]]), color=\"#330000\", linestyle='dashed', label=f\"Effective voltage {framework_name_2}\", marker='None', zorder=10)\n", + " axes[0].legend()\n", + " # Set x-ticks (to integer values only)\n", + " axes[0].set_xticks(np.arange(min(data_stacked_1[:,0]), np.ceil(max(data_stacked_1[:,0])) + 1, step=2))\n", + " axes[0].set_xticks(np.arange(min(data_stacked_1[:,0]), np.ceil(max(data_stacked_1[:,0])) + 1, step=1), minor=True)\n", + "\n", + " # Plot spikes\n", + " axes[1].set_xlabel(\"Time (steps)\")\n", + " axes[1].set_ylabel(f\"Spikes\")\n", + " # Get logical masks\n", + " mask_1 = data_stacked_1[:,X_cols[\"spike\"]] > 0.5\n", + " mask_2 = data_stacked_2[:,X_cols[\"spike\"]] > 0.5\n", + " axes[1].plot(data_stacked_1[:,0][mask_1], data_stacked_1[:,X_cols[\"spike\"]][mask_1], color=\"#ff0000\", marker='o', \n", + " linestyle='none', label=framework_name_1, zorder=9)\n", + " axes[1].plot(data_stacked_2[:,0][mask_2], data_stacked_2[:,X_cols[\"spike\"]][mask_2], color=\"#330000\", marker='o', markerfacecolor='none', \n", + " linestyle='none', label=framework_name_2, zorder=10)\n", + " axes[1].tick_params(left = False, labelleft = False)\n", + " axes[1].legend()\n", + "\n", + " # Save figure as vector graphics\n", + " fig.savefig(store_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Running the simulations" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PyATRLIFModelFloat initialized\n", + "PyATRLIFModelFixed initialized\n", + "PyATRLIFModelFloat initialized\n", + "PyATRLIFModelFixed initialized\n" + ] + } + ], + "source": [ + "# Simulate with default values in floating- and fixed-point implementation\n", + "simulation_test(Loihi2SimCfg(select_tag=\"floating_pt\"),\n", + " \"cpu-float\")\n", + "simulation_test(Loihi2SimCfg(select_tag=\"fixed_pt\"),\n", + " \"cpu-fixed\",\n", + " bias_exp=6)\n", + "\n", + "# Simulate with constant threshold dynamics in floating- and fixed-point implementation\n", + "simulation_test(Loihi2SimCfg(select_tag=\"floating_pt\"),\n", + " \"cpu-float_theta_const\",\n", + " delta_theta=0,\n", + " theta_step=0)\n", + "simulation_test(Loihi2SimCfg(select_tag=\"fixed_pt\"),\n", + " \"cpu-fixed_theta_const\",\n", + " delta_theta=0,\n", + " theta_step=0,\n", + " bias_exp=6)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plotting the results from default setting\n", + "_The membrane voltage minus the value of the refractory state yields the effective voltage, which is compared against the threshold value to determine spiking._\n", + "\n", + "_The dynamics of the threshold hampers spiking if the last spike occurred not too long ago._" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "data_stacked_cpu_float = np.loadtxt(f'./results/atrlif_v_cpu-float.txt')\n", + "data_stacked_cpu_fixed = np.loadtxt(f'./results/atrlif_v_cpu-fixed.txt')\n", + "\n", + "plot(data_stacked_cpu_float, data_stacked_cpu_fixed, \"CPU floating-pt.\", \"CPU fixed-pt.\", \n", + " {\"voltage\": 1, \"ref\": 2, \"theta\": 3, \"spike\": 4},\n", + " store_path = f\"./results/atrlif_cpu-float_cpu-fixed.svg\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plotting the results from constant threshold setting\n", + "_The membrane voltage minus the value of the refractory state yields the effective voltage, which is compared against the threshold value to determine spiking._\n", + "\n", + "_Here, the threshold value remains constant, which essentially yields the dynamics of a standard LIF neuron (with refractoriness)._" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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JyckFOnzd370EQA1wsIo4aLe70I4iz4qCgBTEb8fbmTbsmV5y6TALT17OuUavqxevXoF7+e3vcxvgwlQoUKF/7d352FRlf0fx9/DjqzuiKK4i/u+575kZZnlnoqllblrpj0+ZelTZmWpZdrqUmpWLlnmkqZmuONuiEqglqi5AKIgCuf3BzA/R0BBlnHg87quuXTOuc8533uY5Tv33Is5gYXkrgKxsbEULVoUd3d38y08PJywlH7RY8eOZfDgwXTo0IF33nnHvD1VoUKFzAls6nVTrxkTE8PZs2dp0aKFxTEtWrQgJCQk3TqEhITQpEkTi23NmjW7a72z2qrdvHlz3N3dKVy4MAcPHmTZsmWUTFnBMTeFhITc87HYuHEjrin1GTd4MP379+fSpUtcv349y9e7/fng5uaGp6cnR3buBKCUlxcN70jc70zkb39OvPjii+btZcuWNSewkPz3SUpKsui+IvdPLbGSaYVTpjO5kvLTWVbt2LABgOb16uVYTCLW0rhqVZyOHaN+Ln2gb12wAIDWnp5wj5HeecEee570ts60ePbc32o+d3P7z/ypk67fPjjIzc3NonxsbCylSpVKt89i6k/wb7zxBn379mXNmjWsXbuWyZMn8+233/JkynSCjncsVGEymXKlq8TdVEmZLvHYsWP3THgBli1bRvXq1SlatGiargaenp7m/p23i4qKwivlS15uiYiI4LHHHqO/oyPcuMEz3bvTt1MnnnvuORISErK8VPKdfxvHpCROpPSvveHvf8/jb5/2zFOziOQZtcRKphVJ+bkjKp03rXtJunmTHadPA9Csb98cjUvEGlo0bMgwoFkufGDdTEhg1549ALTq3BkegFWzTCYTDiYHq9wehFXD6tevz7lz53BwcKBSpUoWt2Kp85WSnCSOGTOGDRs20L17d+bPn5+p83t6euLr60tQUJDF9qCgIKpXr57uMQEBAezevdti286U1sOMdOrUiWLFivHuu++mu//OgUp+fn5UrFgx3b6yVatWJTg4OM32ffv2mZPl+xUQEHDXxyI4OJikpCR8U79Exsdz9uxZi/JOTk7m5ZOzqlpCAgYQYGeHXdu2aQbo7Ul5faa6/fmQ2l0C4PTp0xZx7dy5Ezs7O6pWrZrtGEVJrGSBd8pPIpdTvp1mxbFvviHKMHADag8alMORiVhBauKSnSnnMuDo4MB3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/cTTE7p/P+djYnABGj37bM4Fl0sGjBzAgJEDuBp71bxt9YbVDBg5gC+//dKi7JCXhzBg5AAuXv7/n3nXb17PgJEDmLdonkXZYf8ZxoCRA/jn3D/mbVu2b8mdSgCTJk1ixowZ7N27FwcHB56947E/efIky5cvZ8WKFeY+lD169ODChQusXbuW4OBg6tevT/v27bmcMltLv379KFOmDHv27CE4OJiJEyfieNuvVtevX+f999/n66+/5vfff+f06dMWrcOzZs1ixowZvP/++xw6dIjOnTvz+OOPc+LEiXTrcObMGbp3707Xrl05cOAAgwcPZuLEiXet9/r167l48SKvvPJKuvvv1i/VNWVe5Oy0TN/+hWH58uVERkbSvHlzizImk4mFCxeyZ88eZs+eDcCLL75I6dKlzUns4sWLef3113nrrbfo//zzAFy+epWFCxcCya29jz32GNWrVyc4OJg33ngjw5b4+VOmEAh85e9PorMz169f56233mLRokUEBQURFRVF7969AejVqxfjxo2jRo0a5hb+Xr163ffjIdmj2Qkka0wm1ri5cTYhga6HD+NTrlyaIjcuXmTvpUsAtBgyJK8jFMkzLmXL4gzcAKL++YdCVatm+RxbFy0CoBng3K1bToYnd/HWW2/RunVrACZOnMijjz5KfHy8udU1ISGBRYsWUbx4cQD++OMPdu/ezYULF3BOWant/fffZ9WqVfzwww88//zznD59mvHjx1OtWjUAKleubHHNmzdvMm/ePCqmfPkZPnw4U6ZMMe9///33mTBhgjlhmj59Ops3b2bmzJnMmTMnTR3mzp1LxYoVmTFjBgBVq1bl8OHDTJ8+PcN6pybEqTFmVlRUFFOnTsXd3Z3G2ZhD1cnJydxtoEiRIvikzHhzp9KlS/Ppp58yYMAAzp07xy+//ML+/ftxSOmvOnnyZGbMmEH37t05cu4cAAl2dnz66acMHDiQJUuWkJSUxJdffomLiws1atTg77//ZujQoRbXuREfz46U+Zmb9+jBbpL/Th9//DFNmjQBYOHChQQEBLB7924aN26Mu7s7Dg4OGcYueUdJrGTZ13FxnARqHTyIz2OPpdl/YO5c4oHi9vZU1ChPycdMXl54A+dJXi3I936S2B9+AKBVlSr/P0DlAbZodnLS7ezkbN72eKfHeaT9I9jbWY4O//z9zwFwcnQyb+vc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5i/M90NJrIiIpGEymShVqhTh4eGcOnXK2uGISD7j7e2Nj49Pts6hJFZERNLl5ORE5cqV1aVARHKUo6NjtlpgUymJFRGRDNnZ2WnZWRF5IKmTk4iIiIjYHCWxIiIiImJzlMSKiIiIiM0pUH1iUyfWjYmJsXIkIiIiIpKe1DztXgsiFKgk9urVqwD4+flZORIRERERuZurV6/i5eWV4X6TUYDWFExKSuLs2bN4eHhgMply/XoxMTH4+flx5swZPD09c/16AI0aNWLPnj15cq38Xj/I/3VU/XKenqM5S/XLHfm9jqpfzrFG/QzD4OrVq/j6+t51oZUC1RJrZ2dHmTJl8vy6np6eefaHt7e3z9M3Qsj/9YP8X0fVL+foOZo7VL+cld/rqPrlvLx+jt6tBTaVBnblM8OGDbN2CLkqv9cP8n8dVT/bl9/rmN/rB/m/jqpfwVCguhPktZiYGLy8vIiOjrZKy0xuy+/1g/xfR9XP9uX3Oqp+ti+/11H1sx61xOYiZ2dnJk+ejLOzs7VDyRX5vX6Q/+uo+tm+/F5H1c/25fc6qn7Wo5ZYEREREbE5aokVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmOFg7gLyUlJTE2bNn8fDwwGQyWTscEREREbmDYRhcvXoVX19f7Owybm8tUEns2bNn8fPzs3YYIiIiInIPZ86coUyZMhnuL1BJrIeHB5D8oHh6elo5GhERERG5U0xMDH5+fua8LSMFKolN7ULg6empJFZERETkAXavrp8a2CUiIiIiNkdJrIiIiIjYHCWxIiIiImJzClSfWBEREbFkGAa3bt0iMTHR2qFIAWFvb4+Dg0O2pztVEisiIlJAJSQkEBkZyfXr160dihQwhQoVolSpUjg5Od33OZTEioiIFEBJSUmEh4djb2+Pr68vTk5OWghIcp1hGCQkJPDvv/8SHh5O5cqV77qgwd0oiRURESmAEhISSEpKws/Pj0KFClk7HClAXF1dcXR05NSpUyQkJODi4nJf59HALhERkQLsflvBRLIjJ553euaKiIiIiM1REisiIiKSRceOHaNp06a4uLhQt25dIiIiMJlMHDhwINevHRgYSLdu3XL9Og86JbEiIiKSPYmJsGULLF2a/G8eTNd17tw5RowYQYUKFXB2dsbPz4+uXbuyadMmcxl/f39MJhMmkwk3Nzfq16/P999/b96fUTK4ZcsWTCYTUVFRGV5/8uTJuLm5ERoaanHNnJRRYjxr1iwWLFiQK9fMqgULFuDt7W2VayuJFRERkfu3YgX4+0PbttC3b/K//v7J23NJREQEDRo04LfffuO9997j8OHDrFu3jrZt2zJs2DCLslOmTCEyMpL9+/fTqFEjevXqxfbt27MdQ1hYGC1btqRcuXIULVo02+fLCi8vL6sljg8SJbEiIiJyf1asgKefhr//ttz+zz/J23MpkX3ppZcwmUzs3r2bp556iipVqlCjRg3Gjh3Lzp07Lcp6eHjg4+NDlSpVmDNnDq6urvz000/Zur7JZCI4OJgpU6ZgMpl444030i23detWGjdujLOzM6VKlWLixIncunXLvH/dunW0bNkSb29vihYtymOPPUZYWJh5f/ny5QGoV68eJpOJNm3aAGlbkNu0acPIkSN55ZVXKFKkCD4+PmliOnbsGC1btsTFxYXq1auzceNGTCYTq1atyrCeqS3Sa9asoXbt2ri4uNC0aVOOHDli3j9o0CCio6PNLd4ZPRa5QUmsiIiIZF1iIowaBYaRdl/qttGjc7xrweXLl1m3bh3Dhg3Dzc0tzf67tVA6ODjg6OhIQkJCtmKIjIykRo0ajBs3jsjISF5++eU0Zf755x8eeeQRGjVqxMGDB5k7dy5ffvkl//vf/8xlrl27xtixY9m7dy+bNm3Czs6OJ598kqSkJAB2794NwMaNG4mMjGTFXb4ULFy4EDc3N3bt2sW7777LlClT+PXXXwFITEykW7duFCpUiF27dvHZZ58xadKkTNd3/PjxzJgxgz179lC8eHG6du3KzZs3ad68OTNnzsTT05PIyMgMH4vconliRUREJOu2bUvbAns7w4AzZ5LLpbQg5oSTJ09iGAbVqlXL0nEJCQnMmDGD6Oho2rVrl60YfHx8cHBwwN3dHR8fHwAuXrxoUeaTTz7Bz8+Pjz/+GJPJRLVq1Th79iwTJkzg9ddfx87OjqeeesrimK+++orixYvz559/UrNmTYoXLw5A0aJFzdfJSO3atZk8eTIAlStX5uOPP2bTpk107NiRX3/9lbCwMLZs2WI+z1tvvUXHjh0zVd/Jkyebyy5cuJAyZcqwcuVKevbsiZeXFyaT6Z7x5Qa1xIqIiEjWRUbmbLlMMtJr+b2LCRMm4O7uTqFChZg+fTrvvPMOjz76aI7GlJ6QkBCaNWtmsQpaixYtiI2N5e+U5P/EiRP06dOHChUq4Onpib+/PwCnT5/O8vVq165tcb9UqVJcuHABgNDQUPz8/CwSzcaNG1uU79KlC+7u7ri7u1OjRg2Lfc2aNTP/v0iRIlStWpWQkJAsx5jT1BIrIiIiWVeqVM6Wy6TKlStjMpk4duxYpsqPHz+ewMBA3N3dKVmypEVS6enpyalTp9IcExUVhb29fbrdFXJS165dKVeuHJ9//jm+vr4kJSVRs2bN++ru4OjoaHHfZDKZuyVkxhdffEFcXFy653pQqSVWREREsu6hh6BMGbgtKbRgMoGfX3K5HFSkSBE6d+7MnDlzuHbtWpr9d06LVaxYMSpVqoSPj49FAgtQtWpVjh49yo0bNyy279u3j/Lly2crmQsICGDHjh0WLcdBQUF4eHhQpkwZLl26RGhoKP/9739p3749AQEBXLlyxeIcTk5OQHKf1uyoWrUqZ86c4fz58+Zte/bssShTunRpKlWqRKVKlShXrpzFvtsHy125coXjx48TEBBgjjG78d0vJbEiIiKSdfb2MGtW8v/vTGRT78+cmVwuh82ZM4fExEQaN27M8uXLOXHiBCEhIcyePdvip+976devHyaTiQEDBhAcHMzJkyf56quvmDlzJuPGjctWjC+99BJnzpxhxIgRHDt2jB9//JHJkyczduxY7OzsKFy4MEWLFuWzzz7j5MmT/Pbbb4wdO9biHCVKlMDV1ZV169Zx/vx5oqOj7yuWjh07UrFiRQYOHMihQ4cICgriv//9L0CaxD49U6ZMYdOmTRw5coTAwECKFStmnh3B39+f2NhYNm3axMWLF7l+/ToAr776KgMGDLiveDNLSayIiIjcn+7d4YcfoHRpy+1lyiRv7949Vy5boUIF9u3bR9u2bRk3bhw1a9akY8eObNq0iblz52b6PN7e3mzbto2bN2/y+OOPU7duXWbPns0HH3zACy+8kK0YS5cuzS+//MLu3bupU6cOL774Is8995w5ebSzs+Pbb78lODiYmjVrMmbMGN577z2Lczg4ODB79mw+/fRTfH19eeKJJ+4rFnt7e1atWkVsbCyNGjVi8ODB5tkJXFxc7nn8O++8w6hRo2jQoAHnzp3jp59+MrcSN2/enBdffJFevXpRvHhx3n33XSB5Bof76dubFSYjqz2kbVhMTAxeXl5ER0fj6elp7XBERESsJj4+nvDwcMqXL5+pROauEhOTZyGIjEzuA/vQQ7nSAis5JygoiJYtW3Ly5EkqVqyYbpktW7bQtm1brly5kuOLK9zt+ZfZfE0Du0RERCR77O1zdBotyXkrV67E3d2dypUrc/LkSUaNGkWLFi0yTGBtgZJYERERkXzu6tWrTJgwgdOnT1OsWDE6dOjAjBkzrB1WtiiJFREREcnnBgwYkOWBVm3atMnyvLx5SQO7RERERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREQki44dO0bTpk1xcXGhbt26REREYDKZOHDgQK5e19/fn5kzZ+bqNWyFklgRERHJlsTERPZu2cK6pUvZu2ULiYmJuX7Nc+fOMWLECCpUqICzszN+fn507dqVTZs2mcv4+/tjMpkwmUy4ublRv359vv/+e/P+wMBAunXrlubcW7ZswWQyERUVleH1J0+ejJubG6GhoWzatAk/Pz8iIyOpWbNmTlYzV2SmfrZAix2IiIjIffttxQpmjhvH2YgI8zZff39Gz5hBu+7dc+WaERERtGjRAm9vb9577z1q1arFzZs3Wb9+PcOGDePYsWPmslOmTGHIkCHExMQwY8YMevXqRenSpWnevHm2YggLC+PRRx+lXLly5m0+Pj7ZOqdkjVpiRURE5L78tmIFE55+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cOEC3t7e2ZpPWEmsiIhIAeXj4wNgTmRF8oq3t7f5+Xe/lMSKiIgUUCaTiVKlSlGiRAlu3rxp7XCkgHB0dMyRFd2UxIqIiBRw9vb2WiZWbI4GdomIiIiIzVESKyIiIiI2R0msiIiIiNgcm09io6KirB2CiIiIiOQxm0pip0+fzrJly8z3e/bsSdGiRSldujQHDx60YmQiIiIikpdsKomdN28efn5+APz666/8+uuvrF27li5dujB+/HgrRyciIiIiecWmptg6d+6cOYn9+eef6dmzJ506dcLf358mTZpYOToRERERySs21RJbuHBhzpw5A8C6devo0KEDkLyEWWJiojVDExEREZE8ZFMtsd27d6dv375UrlyZS5cu0aVLFwD2799PpUqVrBydiIiIiOQVm0piP/zwQ/z9/Tlz5gzvvvsu7u7uAERGRvLSSy9ZOToRERERySsmwzAMaweRV2JiYvDy8iI6OhpPT09rhyMiIiIid8hsvmZTfWIBvv76a1q2bImvry+nTp0CYObMmfz4449WjkxERERE8opNJbFz585l7NixdOnShaioKPNgLm9vb2bOnGnd4EREREQkz9hUEvvRRx/x+eefM2nSJOzt7c3bGzZsyOHDh60YmYiIiIjkJZtKYsPDw6lXr16a7c7Ozly7ds0KEYmIiIiINdhUElu+fHkOHDiQZvu6desICAjI+4BERERExCpsaoqtsWPHMmzYMOLj4zEMg927d7N06VKmTZvGF198Ye3wRERERCSP2FQSO3jwYFxdXfnvf//L9evX6du3L76+vsyaNYvevXtbOzwRERERySM2NU9sTEyMeb6w69evExsbS4kSJQA4efLkPVft0jyxIiIiIg+2zOZrNtUS++ijj7Jx40acnZ0pVKgQhQoVAiA0NJT27dvz999/WznCgiMxIYH9n3zCxbAwilWsSL2XXsLeycnaYYlYjV4TItan12HBYlMtsV26dMFkMrF69WocHJLz75CQENq1a0fPnj2ZNWvWXY9XS2zO+O2VV5j5wQecTZmnF8DX3p7RY8fS7t13rRiZiHXoNSFifXod5h/5csWuFStWEB0dTb9+/TAMgyNHjtCmTRv69OlzzwRWcsZvr7zChPfeo2JiIvOB34H5QMXERCa89x6/vfKKlSMUyVt6TYhYn16HBZNNtcQCREVF0aZNGypXrszvv//OgAEDeO+99zJ1rFpisycxIYEnCxWiYmIiM7D8BpQEjAP+srdnxfXr+vlGCgS9JkSsT6/D/CfftMTGxMRY3Ozs7Fi2bBm7du3iqaee4rXXXjPvk9y1/5NPOJuYyLOkfeLYAYOAfxIT2f/JJ3kfnIgV6DUhYn16HRZcD/zALm9vb0wmU5rthmEwb948Pv30UwzDwGQykXhbPxjJeRfDwgComMH+ineUE8nv9JoQsT69DguuBz6J3bx5s7VDkBTFKia/FYQBtdLZH3ZHOZH8Tq8JEevT67Dgsrk+sdmhPrHZo35HIpb0mhCxPr0O85980yf20KFDJCUlmf9/t5vkLnsnJ0aPHcsfJL8pHAKupfw7DvgDGDV2rN4kpMDQa0LE+vQ6LLge+JZYOzs7zp07R4kSJbCzs8NkMpFeyJnpE6uW2JyR3lx8pe3tGaW5+KSA0mtCxPr0Osw/MpuvPfBJ7KlTpyhbtiwmk4lTp07dtWy5cuXuul9JbM7RqigilvSaELE+vQ7zh3yTxOYkJbEiIiIiD7bM5msP/OwEdwoNDeWjjz4iJCQEgICAAEaMGEHVqlWtHJmIiIiI5JUHfmDX7ZYvX07NmjUJDg6mTp061KlTh3379lGzZk2WL19u7fBEREREJI/YVHeCihUr0q9fP6ZMmWKxffLkyXzzzTeE3WMiY3UnEBEREXmw5Zsptm4XGRnJgAED0mx/5plniIyMtEJEIiIiImINNpXEtmnThm3btqXZ/scff/DQQw9ZISIRERERsQabGtj1+OOPM2HCBIKDg2natCkAO3fu5Pvvv+fNN99k9erVFmVFREREJH+yqT6xdnaZazjOaOED9YkVERERebDlyym2UpefFREREZGCzSb6xO7YsYOff/7ZYtuiRYsoX748JUqU4Pnnn+fGjRtWik5ERERE8ppNJLFTpkzh6NGj5vuHDx/mueeeo0OHDkycOJGffvqJadOmWTFCEREREclLNpHEHjhwgPbt25vvf/vttzRp0oTPP/+csWPHMnv2bL777jsrRigiIiIieckmktgrV65QsmRJ8/2tW7fSpUsX8/1GjRpx5swZa4QmIiIiIlZgE0lsyZIlCQ8PByAhIYF9+/aZp9gCuHr1Ko6OjtYKT0RERETymE0ksY888ggTJ05k27ZtvPrqqxQqVMhicYNDhw5RsWJFK0YoIiIiInnJJqbYmjp1Kt27d6d169a4u7uzcOFCnJyczPu/+uorOnXqZMUIRURERCQv2dRiB9HR0bi7u2Nvb2+x/fLly7i7u1sktunRYgciIiIiD7Z8udiBl5dXutuLFCmSx5GIiIiIiDXZRJ9YEREREZHbKYkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6SWBERERGxOUpiRURERMTmKIkVEREREZujJFZEREREbI6DtQPIS4ZhABATE2PlSEREREQkPal5WmrelpEClcRevXoVAD8/PytHIiIiIiJ3c/XqVby8vDLcbzLulebmI0lJSZw9exYPDw9MJlOuXy8mJgY/Pz/OnDmDp6dnrl8PoFGjRuzZsydPrpXf6wf5v46qX87TczRnqX65I7/XUfXLOdaon2EYXL16FV9fX+zsMu75WqBaYu3s7ChTpkyeX9fT0zPP/vD29vZ5+kYI+b9+kP/rqPrlHD1Hc4fql7Pyex1Vv5yX18/Ru7XAptLArnxm2LBh1g4hV+X3+kH+r6PqZ/vyex3ze/0g/9dR9SsYClR3grwWExODl5cX0dHRVmmZyW35vX6Q/+uo+tm+/F5H1c/25fc6qn7Wo5bYXOTs7MzkyZNxdna2dii5Ir/XD/J/HVU/25ff66j62b78XkfVz3rUEisiIiIiNkctsSIiIiJic5TEioiIiIjNURIr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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "data_stacked_cpu_float = np.loadtxt(f'./results/atrlif_v_cpu-float_theta_const.txt')\n", + "data_stacked_cpu_fixed = np.loadtxt(f'./results/atrlif_v_cpu-fixed_theta_const.txt')\n", + "\n", + "plot(data_stacked_cpu_float, data_stacked_cpu_fixed, \"CPU floating-pt.\", \"CPU fixed-pt.\", \n", + " {\"voltage\": 1, \"ref\": 2, \"theta\": 3, \"spike\": 4},\n", + " store_path = f\"./results/atrlif_theta_const_cpu-float_cpu-fixed.svg\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/tutorials/lava_va/Tutorial01-Fixed_point_dot_product.ipynb b/tutorials/lava_va/Tutorial01-Fixed_point_dot_product.ipynb new file mode 100644 index 000000000..fbed7bd78 --- /dev/null +++ b/tutorials/lava_va/Tutorial01-Fixed_point_dot_product.ipynb @@ -0,0 +1,672 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3cd2e32f", + "metadata": {}, + "source": [ + "*Copyright (C) 2022-23 Intel Corporation*
\n", + "*SPDX-License-Identifier: BSD-3-Clause*
\n", + "*See: https://spdx.org/licenses/*\n", + "\n", + "---\n", + "\n", + "# Tutorial 1: An Introduction to Graded Spikes and Fixed-point computations\n", + "\n", + "**Motivation:** In this tutorial, we will discuss the basics of Lava vector algebra API and computing with graded spikes on Loihi 2. This tutorial will demonstrate simple dot-product matrix operations using graded spikes.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "72b82564", + "metadata": {}, + "outputs": [], + "source": [ + "from pylab import *" + ] + }, + { + "cell_type": "markdown", + "id": "816aceb0", + "metadata": {}, + "source": [ + "Lava-VA includes a new set of processes that are compatible with Loihi 2. \n", + "\n", + "First, we can import some of the standard library using an import package. These are designed to make importing the standard libraries more simple and accessible.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "af469544", + "metadata": {}, + "outputs": [], + "source": [ + "import lava.frameworks.loihi2 as lv" + ] + }, + { + "cell_type": "markdown", + "id": "3a39c84c", + "metadata": {}, + "source": [ + "Next, we'll get access to Loihi 2, or we can use the CPU backend." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cf6e92dd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running on Loihi 2\n" + ] + } + ], + "source": [ + "from lava.utils import loihi\n", + "\n", + "loihi.use_slurm_host(loihi_gen=loihi.ChipGeneration.N3B3)\n", + "use_loihi2 = loihi.is_installed()\n", + "\n", + "if use_loihi2:\n", + " run_cfg = lv.Loihi2HwCfg()\n", + " print(\"Running on Loihi 2\")\n", + "else:\n", + " run_cfg = lv.Loihi2SimCfg(select_tag='fixed_pt')\n", + " print(\"Loihi2 compiler is not available in this system. \"\n", + " \"This tutorial will execute on CPU backend.\")" + ] + }, + { + "cell_type": "markdown", + "id": "d2816267", + "metadata": {}, + "source": [ + "Now, lets setup some inputs, and create the structure for our Loihi 2 algorithm. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "9c3c5a76", + "metadata": {}, + "outputs": [], + "source": [ + "vec = np.array([40, 30, 20, 10])\n", + "weights = np.zeros((3,4))\n", + "weights[:, 0] = [8, 9, -7]\n", + "weights[:, 1] = [9, 8, -5]\n", + "weights[:, 2] = [8, -10, -4]\n", + "weights[:, 3] = [8, -10, -3]\n", + "\n", + "# Note: we define the weights using floating points,\n", + "# this will create the equivalent fixed-point \n", + "# representation on Loihi 2. We use the weight_exp to \n", + "# set the dynamic range. The dynamic range is:\n", + "# weight_exp = 8 -- [-1, 1)\n", + "# weight_exp = 7 -- [-2, 2)\n", + "# weight_exp = 6 -- [-4, 4)\n", + "# ...\n", + "# weight_exp = 1 -- [-128, 128)\n", + "weights /= 10\n", + "weight_exp = 7" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "48b567d1", + "metadata": {}, + "outputs": [], + "source": [ + "num_steps=16" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "09c97cca", + "metadata": {}, + "outputs": [], + "source": [ + "inp_data = np.zeros((vec.shape[0], num_steps))\n", + "inp_data[:, 1] = vec.ravel()\n", + "inp_data[:, 3] = 4*vec.ravel()\n", + "inp_data[:, 5] = 16*vec.ravel()\n", + "inp_data[:, 7] = 64*vec.ravel()\n", + "inp_data[:, 9] = 256*vec.ravel()" + ] + }, + { + "cell_type": "markdown", + "id": "41d911d8", + "metadata": {}, + "source": [ + "In this case, I have created an input vector and some weights, and then I will send the input vector in with different magnitudes at different timesteps." + ] + }, + { + "cell_type": "markdown", + "id": "e88436b4", + "metadata": {}, + "source": [ + "Next, we use the standard library to create the input layer, the synaptic weights, the neuron layer, and the readout layer." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "7590a9fc", + "metadata": {}, + "outputs": [], + "source": [ + "invec = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "\n", + "in_out_syn = lv.GradedDense(weights=weights, exp=weight_exp)\n", + "\n", + "outvec = lv.GradedVec(shape=(weights.shape[0],), vth=1)\n", + "\n", + "out_monitor = lv.OutputVec(shape=outvec.shape, buffer=num_steps, loihi2=use_loihi2)\n" + ] + }, + { + "cell_type": "markdown", + "id": "129d701b", + "metadata": {}, + "source": [ + "There is a new interface that includes the ability to incorporate operator overloading. This allows constructions of Networks based on an algebraic syntax.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "97e62916", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "outvec << in_out_syn @ invec\n", + "out_monitor << outvec" + ] + }, + { + "cell_type": "markdown", + "id": "a7b70c79", + "metadata": {}, + "source": [ + "Now we can run the network." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "6b2c0862", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " outvec.run(condition=lv.RunSteps(num_steps=num_steps),\n", + " run_cfg=run_cfg)\n", + " out_data = out_monitor.get_data()\n", + "finally:\n", + " outvec.stop()" + ] + }, + { + "cell_type": "markdown", + "id": "0668d3be", + "metadata": {}, + "source": [ + "What we should see is the dot product of the input vector. Since we incremented the input strength, the entire vector output will also grow proportionally." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "c3cad817", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 83, 331, 1321, 5280, 21120],\n", + " [ 30, 119, 473, 1890, 7560],\n", + " [ -54, -218, -868, -3470, -13880]], dtype=int32)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_data[:,2:11:2]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "552f017a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 83., 30., -54.])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weights @ vec" + ] + }, + { + "cell_type": "markdown", + "id": "c53991fb", + "metadata": {}, + "source": [ + "There may be some rounding differences due to the rounding of the values, but we see the correct values compared to the numpy calculation." + ] + }, + { + "cell_type": "markdown", + "id": "a93b4a44", + "metadata": {}, + "source": [ + "## Addition operator overload\n", + "\n", + "As a second example we will create two weight matrices and show how the additionn operator overload can be used.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "dd826827", + "metadata": {}, + "outputs": [], + "source": [ + "# Defining two input streams\n", + "vec = np.array([40, 30, 20, 10])\n", + "weights = np.zeros((3,4))\n", + "weights[:, 0] = [8, 9, -7]\n", + "weights[:, 1] = [9, 8, -5]\n", + "weights[:, 2] = [8, -10, -4]\n", + "weights[:, 3] = [8, -10, -3]\n", + "\n", + "vec2 = np.array([50, -50, 20, -20])\n", + "weights2 = np.zeros((3,4))\n", + "weights2[:, 0] = [3, -5, 4]\n", + "weights2[:, 1] = [0, -2, -10]\n", + "weights2[:, 2] = [6, 8, -4]\n", + "weights2[:, 3] = [-5, 7, -7]\n", + "\n", + "weights /= 10\n", + "weights2 /= 10\n", + "\n", + "weight_exp = 7\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "1802b046", + "metadata": {}, + "outputs": [], + "source": [ + "num_steps=16\n", + "\n", + "inp_data = np.zeros((vec.shape[0], num_steps))\n", + "inp_data[:, 1] = vec.ravel()\n", + "inp_data[:, 3] = 4*vec.ravel()\n", + "inp_data[:, 5] = 16*vec.ravel()\n", + "inp_data[:, 7] = 64*vec.ravel()\n", + "inp_data[:, 9] = 256*vec.ravel()\n", + "\n", + "inp_data2 = np.zeros((vec2.shape[0], num_steps))\n", + "inp_data2[:, 1] = vec2.ravel()\n", + "inp_data2[:, 3] = 4*vec2.ravel()\n", + "inp_data2[:, 5] = 16*vec2.ravel()\n", + "inp_data2[:, 7] = 64*vec2.ravel()\n", + "inp_data2[:, 9] = 256*vec2.ravel()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "a108c232", + "metadata": {}, + "outputs": [], + "source": [ + "# instantiate the objects\n", + "invec1 = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "invec2 = lv.InputVec(inp_data2, loihi2=use_loihi2)\n", + "\n", + "in_out_syn1 = lv.GradedDense(weights=weights, exp=weight_exp)\n", + "in_out_syn2 = lv.GradedDense(weights=weights2, exp=weight_exp)\n", + "\n", + "outvec = lv.GradedVec(shape=(weights.shape[0],), vth=1)\n", + "\n", + "out_monitor = lv.OutputVec(shape=outvec.shape, buffer=num_steps, loihi2=use_loihi2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "5c7e9258", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# compute the dot product of both input streams and add together\n", + "outvec << in_out_syn1 @ invec1 + in_out_syn2 @ invec2\n", + "out_monitor << outvec" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "e44b8e6f", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " outvec.run(condition=lv.RunSteps(num_steps=num_steps),\n", + " run_cfg=run_cfg) # Loihi2SimCfg(select_tag='fixed_pt')\n", + " out_data = out_monitor.get_data()\n", + "finally:\n", + " outvec.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "b0c7abf8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 120, 478, 1909, 7630, 30520],\n", + " [ 17, 69, 271, 1080, 4320],\n", + " [ 22, 83, 340, 1360, 5440]], dtype=int32)" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_data[:,2:11:2]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "97106421", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([120., 17., 22.])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weights @ vec + weights2 @ vec2" + ] + }, + { + "cell_type": "markdown", + "id": "3ebf3be9", + "metadata": {}, + "source": [ + "Again we see the output results matching the numpy calculations, perhaps with some differences due to rounding." + ] + }, + { + "cell_type": "markdown", + "id": "4f773ae8", + "metadata": {}, + "source": [ + "## More algebra syntax\n", + "\n", + "Another function that occurs under-the-hood is the creation of Identity connections when connecting vectors. \n", + "\n", + "This can also be supported with the addition operator.\n", + "\n", + "Just have to make sure the vector shapes are correct!" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "aa7f0c48", + "metadata": {}, + "outputs": [], + "source": [ + "# Defining two input streams\n", + "vec = np.array([40, 30, 20, 10])\n", + "weights = np.zeros((4,4))\n", + "weights[:, 0] = [8, 9, -7, -2]\n", + "weights[:, 1] = [9, 8, -5, 2]\n", + "weights[:, 2] = [8, -10, -4, 5]\n", + "weights[:, 3] = [8, -10, -3, -9]\n", + "\n", + "vec2 = np.array([50, -50, 20, -20])\n", + "weights2 = np.zeros((4,4))\n", + "weights2[:, 0] = [3, -5, 4, -6]\n", + "weights2[:, 1] = [0, -2, -10, 0]\n", + "weights2[:, 2] = [6, 8, -4, 4]\n", + "weights2[:, 3] = [-5, 7, -7, 8]\n", + "\n", + "weights3 = np.random.randint(20, size=(4,4)) - 10\n", + "weights3 = weights3 / 10\n", + "\n", + "weights /= 10\n", + "weights2 /= 10\n", + "\n", + "weight_exp = 7" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "7d7aaff8", + "metadata": {}, + "outputs": [], + "source": [ + "num_steps=16\n", + "\n", + "inp_data = np.zeros((vec.shape[0], num_steps))\n", + "inp_data[:, 1] = vec.ravel()\n", + "inp_data[:, 3] = 4*vec.ravel()\n", + "inp_data[:, 5] = 16*vec.ravel()\n", + "inp_data[:, 7] = 64*vec.ravel()\n", + "inp_data[:, 9] = 256*vec.ravel()\n", + "\n", + "inp_data2 = np.zeros((vec2.shape[0], num_steps))\n", + "inp_data2[:, 1] = vec2.ravel()\n", + "inp_data2[:, 3] = 4*vec2.ravel()\n", + "inp_data2[:, 5] = 16*vec2.ravel()\n", + "inp_data2[:, 7] = 64*vec2.ravel()\n", + "inp_data2[:, 9] = 256*vec2.ravel()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "237a8090", + "metadata": {}, + "outputs": [], + "source": [ + "# instantiate the objects\n", + "invec1 = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "invec2 = lv.InputVec(inp_data2, loihi2=use_loihi2)\n", + "\n", + "in_out_syn1 = lv.GradedDense(weights=weights, exp=weight_exp)\n", + "in_out_syn2 = lv.GradedDense(weights=weights2, exp=weight_exp)\n", + "\n", + "extra_syn = lv.GradedDense(weights=weights3, exp=weight_exp)\n", + "\n", + "intvec1 = lv.GradedVec(shape=(weights.shape[0],), vth=1)\n", + "intvec2 = lv.GradedVec(shape=(weights.shape[0],), vth=1)\n", + "\n", + "outvec = lv.GradedVec(shape=(weights.shape[0],), vth=1)\n", + "out_monitor = lv.OutputVec(shape=outvec.shape, buffer=num_steps, loihi2=use_loihi2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "20055ec5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "intvec1 << in_out_syn1 @ invec1\n", + "intvec2 << in_out_syn2 @ invec2\n", + "\n", + "outvec << intvec1 + intvec2 + extra_syn @ intvec1\n", + "out_monitor << outvec\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "7d9a8b98", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " outvec.run(condition=lv.RunSteps(num_steps=num_steps),\n", + " run_cfg=run_cfg) # Loihi2SimCfg(select_tag='fixed_pt')\n", + " out_data = out_monitor.get_data()\n", + "finally:\n", + " outvec.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "c45ca11b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 168, 670, 2678, 10705, 42817],\n", + " [ -7, -28, -118, -476, -1900],\n", + " [ 123, 484, 1941, 7757, 31030],\n", + " [ -68, -276, -1103, -4415, -17659]], dtype=int32)" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_data[:,3:12:2]" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "c7c61f8b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([168.8, -7.4, 123.8, -69.6])" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weights @ vec + weights2 @ vec2 + weights3 @ weights @ vec" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4217586c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/lava_va/Tutorial02-Fixed_point_elementwise_product.ipynb b/tutorials/lava_va/Tutorial02-Fixed_point_elementwise_product.ipynb new file mode 100644 index 000000000..e438802d0 --- /dev/null +++ b/tutorials/lava_va/Tutorial02-Fixed_point_elementwise_product.ipynb @@ -0,0 +1,361 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2e52884c", + "metadata": {}, + "source": [ + "*Copyright (C) 2022-23 Intel Corporation*
\n", + "*SPDX-License-Identifier: BSD-3-Clause*
\n", + "*See: https://spdx.org/licenses/*\n", + "\n", + "---\n", + "\n", + "# Tutorial 2: Elementwise products\n", + "\n", + "**Motivation:** In this tutorial, we will highlight more of the standard library included with Lava-VA. Here we demonstrate the element-wise product of vectors using ProductVec.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "64990f4f", + "metadata": {}, + "source": [ + "First, we make the imports and connect to Loihi 2." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "72b82564", + "metadata": {}, + "outputs": [], + "source": [ + "from pylab import *" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "af33e13b", + "metadata": {}, + "outputs": [], + "source": [ + "import lava.frameworks.loihi2 as lv" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2a68a562", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running on Loihi 2\n" + ] + } + ], + "source": [ + "from lava.utils import loihi\n", + "\n", + "loihi.use_slurm_host(loihi_gen=loihi.ChipGeneration.N3B3)\n", + "use_loihi2 = loihi.is_installed()\n", + "\n", + "if use_loihi2:\n", + " run_cfg = lv.Loihi2HwCfg()\n", + " print(\"Running on Loihi 2\")\n", + "else:\n", + " run_cfg = lv.Loihi2SimCfg(select_tag='fixed_pt')\n", + " print(\"Loihi2 compiler is not available in this system. \"\n", + " \"This tutorial will execute on CPU backend.\")" + ] + }, + { + "cell_type": "markdown", + "id": "c1ff4fcd", + "metadata": {}, + "source": [ + "Next, we will setup the inputs and initialize the input weights." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d0065b52", + "metadata": {}, + "outputs": [], + "source": [ + "num_steps = 10\n", + "weights1 = np.zeros((5,1))\n", + "weights2 = np.zeros((5,1))\n", + "\n", + "weights1[:,0] = [2, 6, 10, -2, -6]\n", + "weights2[:,0] = [4, 8, 12, -4, 8]\n", + "\n", + "weights1 /= 16\n", + "weights2 /= 16\n", + "\n", + "inp_shape = (weights1.shape[1],)\n", + "out_shape = (weights1.shape[0],)\n", + "\n", + "inp_data = np.zeros((inp_shape[0], num_steps))\n", + "inp_data[:, 2] = 16\n", + "inp_data[:, 6] = 32" + ] + }, + { + "cell_type": "markdown", + "id": "5c40fe2e", + "metadata": {}, + "source": [ + "Then we instantiate the objects in the network." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b6f6a23c", + "metadata": {}, + "outputs": [], + "source": [ + "dense1 = lv.GradedDense(weights=weights1)\n", + "dense2 = lv.GradedDense(weights=weights2)\n", + "\n", + "vec = lv.ProductVec(shape=out_shape, vth=1, exp=0)\n", + "\n", + "generator1 = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "generator2 = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "monitor = lv.OutputVec(shape=out_shape, buffer=num_steps,\n", + " loihi2=True)" + ] + }, + { + "cell_type": "markdown", + "id": "5bddeb53", + "metadata": {}, + "source": [ + "In this case, ProductVec is an object that has two input channels. We can access those input channels by concatenating the objects and \"piping\" them into the ProductVec layer. " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "73392fbe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vec << (dense1 @ generator1, dense2 @ generator2)\n", + "monitor << vec" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "aaff1295", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " vec.run(condition=lv.RunSteps(num_steps=num_steps),\n", + " run_cfg=run_cfg)\n", + " out_data = monitor.get_data()\n", + "finally:\n", + " vec.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "154e2cb5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 8, 32],\n", + " [ 48, 192],\n", + " [ 120, 480],\n", + " [ 8, 32],\n", + " [ -48, -192]], dtype=int32)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_data[:, (3,7)]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "af0e7ae4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 8., 48., 120., 8., -48.])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(weights1 @ inp_data[:,2]) * (weights2 @ inp_data[:,2])" + ] + }, + { + "cell_type": "markdown", + "id": "37462a5e", + "metadata": {}, + "source": [ + "We can see that this matches the numpy calculation." + ] + }, + { + "cell_type": "markdown", + "id": "8b442585", + "metadata": {}, + "source": [ + "## Multiplication operator overload\n", + "\n", + "Similar to addition, the multiplication operator is overloaded inside of GradedVec to enable the use of algebraic syntax to compute the elementwise product.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "cfaeb662", + "metadata": {}, + "outputs": [], + "source": [ + "dense1 = lv.GradedDense(weights=weights1)\n", + "dense2 = lv.GradedDense(weights=weights2)\n", + "\n", + "vec1 = lv.GradedVec(shape=out_shape, vth=1, exp=0)\n", + "vec2 = lv.GradedVec(shape=out_shape, vth=1, exp=0)\n", + "\n", + "outvec = lv.GradedVec(shape=out_shape, vth=1, exp=0)\n", + "\n", + "generator1 = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "generator2 = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "monitor = lv.OutputVec(shape=out_shape, buffer=num_steps,\n", + " loihi2=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "709a42d5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vec1 << dense1 @ generator1\n", + "vec2 << dense2 @ generator2\n", + "outvec << vec1 * vec2\n", + "monitor << outvec" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "3a0fc3a4", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " vec1.run(condition=lv.RunSteps(num_steps=num_steps),\n", + " run_cfg=run_cfg)\n", + " out_data = monitor.get_data()\n", + "finally:\n", + " vec1.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "95ca186e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 8],\n", + " [ 48],\n", + " [120],\n", + " [ 8],\n", + " [-48]], dtype=int32)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out_data[:, (5,)] " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e80b63c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/lava_va/Tutorial03-Normalization_network.ipynb b/tutorials/lava_va/Tutorial03-Normalization_network.ipynb new file mode 100644 index 000000000..3651ee8c7 --- /dev/null +++ b/tutorials/lava_va/Tutorial03-Normalization_network.ipynb @@ -0,0 +1,319 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "37ee11cd", + "metadata": {}, + "source": [ + "*Copyright (C) 2022-23 Intel Corporation*
\n", + "*SPDX-License-Identifier: BSD-3-Clause*
\n", + "*See: https://spdx.org/licenses/*\n", + "\n", + "---\n", + "\n", + "# Tutorial 3: Normalization Network\n", + "\n", + "**Motivation:** In this tutorial, we will highlight more of the standard library included with Lava-VA. Here we demonstrate the Normalization network for computing a normalized vector output from a dot product.\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "5822757f", + "metadata": {}, + "outputs": [], + "source": [ + "from pylab import *" + ] + }, + { + "cell_type": "markdown", + "id": "2dc9a58e", + "metadata": {}, + "source": [ + "Here again we setup the imports and connect to Loihi 2." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "086079fb", + "metadata": {}, + "outputs": [], + "source": [ + "import lava.frameworks.loihi2 as lv" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "67b4603d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running on Loihi 2\n" + ] + } + ], + "source": [ + "from lava.utils import loihi\n", + "\n", + "loihi.use_slurm_host(loihi_gen=loihi.ChipGeneration.N3B3)\n", + "use_loihi2 = loihi.is_installed()\n", + "\n", + "if use_loihi2:\n", + " run_cfg = lv.Loihi2HwCfg()\n", + " print(\"Running on Loihi 2\")\n", + "else:\n", + " run_cfg = lv.Loihi2SimCfg(select_tag='fixed_pt')\n", + " print(\"Loihi2 compiler is not available in this system. \"\n", + " \"This tutorial will execute on CPU backend.\")" + ] + }, + { + "cell_type": "markdown", + "id": "fb525826", + "metadata": {}, + "source": [ + "Now we will create some inputs and initialize the weight matrix." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "82d4446c", + "metadata": {}, + "outputs": [], + "source": [ + "num_steps=20\n", + "weights = np.zeros((10,1))\n", + "\n", + "weights[:,0] = [2, 4, -2, -4, 8, 10, -8, -10, 5, -5]\n", + "weights /= 10\n", + "\n", + "inp_data = np.zeros((weights.shape[1], num_steps))\n", + "\n", + "inp_data[:, 2] = 160\n", + "inp_data[:, 5] = 320\n", + "inp_data[:, 8] = 640\n", + "inp_data[:, 11] = 1280\n" + ] + }, + { + "cell_type": "markdown", + "id": "f77b1746", + "metadata": {}, + "source": [ + "In this demo, we set the input stimulus to be of different magnitudes. The inputs will multiply with the weight values, producing a vector output. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "151073fb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0.2],\n", + " [ 0.4],\n", + " [-0.2],\n", + " [-0.4],\n", + " [ 0.8],\n", + " [ 1. ],\n", + " [-0.8],\n", + " [-1. ],\n", + " [ 0.5],\n", + " [-0.5]])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weights" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "678f6873", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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IFZUVMBut8NgMLg8bzAYYDabO3yN2Wz2qL0vOBwOLFiwALfddhuuv/56t+2SkpKwYcMGfPTRR3jrrbfgcDhw66234qeffvJZX1NSUrBp0ybs3LkT69atw7lz53DHHXdItSvbU+L1BoBt27ahuroajz76qNs2Srje7YnXzZNr2pOfE29rbGzEU089hYceeqjTiguefr95y+TJk/Hmm28iNzcXL730Evbu3YspU6bAbrd32F6J13zz5s2IiIjA/fff32k7pVzznrpqyz9dKzIzM3H8+PEu5+lTU1ORmpoqfX3rrbdi5MiReO211/D88897u5sAgClTpkj/Hjt2LFJSUjBo0CC899573frLUyneeOMNTJkyBSaTyW0bJVzvq5HNZsMDDzwAQRCwbt26Ttsq5ftt9uzZ0r/HjBmDsWPHYujQodizZw8mTpzos370xoYNG5CRkdFlYphSrnlPXbMjxNjYWGg0GpSVlbk8X1ZWBqPR2OFrjEajR+29LSsrCzt27MDu3bs9rv0YHByMG264Ad99952Xete1qKgoDB8+3G0flHa9AeD8+fP44osv8B//8R8evU4J11u8bp5c0578nHiLGAzPnz+PnJwcj+vxdfX95itDhgxBbGys234o6ZoDwJdffomioiKPv+cB5Vzz7rpmA6JWq8X48eORm5srPedwOJCbm+vyl31bqampLu0BICcnx217bxEEAVlZWfjwww+xa9cuJCYmenwOu92OY8eOIT4+3gs97J66ujp8//33bvuglOvd1saNGxEXF4dp06Z59DolXO/ExEQYjUaXa2qxWJCfn+/2mvbk58QbxGB49uxZfPHFF4iJifH4HF19v/nKTz/9hMrKSrf9UMo1F73xxhsYP348kpOTPX6tUq55t/k7q8ef3n33XSEkJETYtGmTcPLkSWH+/PlCVFSUYDabBUEQhIcfflh4+umnpfZff/21EBQUJKxYsUI4deqUsHTpUiE4OFg4duyYT/v92GOPCXq9XtizZ49w4cIF6dHQ0CC1ad/35557Tvjss8+E77//XigoKBBmz54t6HQ64cSJEz7r95///Gdhz549wrlz54Svv/5aSEtLE2JjY4Xy8vIO+6yU6y2y2+3CwIEDhaeeeuqKY0q53rW1tcKRI0eEI0eOCACElStXCkeOHJGyMV988UUhKipK+Oijj4Rvv/1WmDFjhpCYmChcvnxZOsc999wjrFmzRvq6q58Tb/fbarUK9913nzBgwAChsLDQ5Xu+qanJbb+7+n7zRd9ra2uFv/zlL0JeXp5w7tw54YsvvhBuvPFGYdiwYUJjY6Pbvvv7motqamqEsLAwYd26dR2ew1/X3Fuu6YAoCIKwZs0aYeDAgYJWqxVuvvlm4cCBA9KxX/ziF8KcOXNc2r/33nvC8OHDBa1WK4wePVr45JNPfNxjZ4p0R4+NGzdKbdr3fcGCBdLnNBgMwtSpU4XDhw/7tN8PPvigEB8fL2i1WqF///7Cgw8+KHz33Xdu+ywIyrjeos8++0wAIBQVFV1xTCnXe/fu3R1+b4h9czgcwuLFiwWDwSCEhIQIEydOvOLzDBo0SFi6dKnLc539nHi73+fOnXP7Pb979263/e7q+80XfW9oaBAmTZok9OvXTwgODhYGDRokzJs374rAprRrLnrttdeE0NBQobq6usNz+OuaewvrIRIREeEavodIRETUFgMiERERGBCJiIgAMCASEREBYEAkIiICwIBIREQEgAGRiIgIAAMiERERAAZEIiIiAAyIREREABgQiYiIAAD/H64bkHOSCymtAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "figure(figsize=(5,3))\n", + "plot(inp_data.T);" + ] + }, + { + "cell_type": "markdown", + "id": "6796f559", + "metadata": {}, + "source": [ + "Note, the increasing amplitude of the input values. Also note the exact timesteps of the input stimulus." + ] + }, + { + "cell_type": "markdown", + "id": "1d8740c8", + "metadata": {}, + "source": [ + "Next, we instantiate the objects from the standard library. The NormalizeNet Network object will act like GradedVec, but its outputs will be normalized. This might be useful for various computations, like the cosine similarity.\n", + "\n", + "Under the hood, NormalizeNet uses a feedback inhibition loop to compute the normalization factor. The sum of squares is sent to an \"inhibitory neuron\", which computes the inverse square root. The inverse square root value is conveyed back to the neuron layer and multiplied with the original input values. The output is then emitted on the primary channel, which is a normalized result of the dot product computation.\n", + "\n", + "Note: because the network receives a recurrent inhibition, each stage takes a timestep. This means that the output is delayed by two timesteps." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "ae30a451", + "metadata": {}, + "outputs": [], + "source": [ + "invec = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "in_w = lv.GradedDense(weights=weights)\n", + "norm_layer = lv.NormalizeNet(shape=(weights.shape[0],))\n", + "monitor = lv.OutputVec(shape=(weights.shape[0],), \n", + " buffer=num_steps,\n", + " loihi2=use_loihi2)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "593678ee", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "norm_layer << in_w @ invec\n", + "monitor << norm_layer" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "b54757ad", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " norm_layer.run(condition=lv.RunSteps(num_steps=num_steps),\n", + " run_cfg=run_cfg)\n", + " out_data = monitor.get_data()\n", + "finally:\n", + " norm_layer.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "9a083710", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Normalized output channel\n", + "figure(figsize=(5,3))\n", + "plot(out_data.T)" + ] + }, + { + "cell_type": "markdown", + "id": "1450dae6", + "metadata": {}, + "source": [ + "This results in the same vector being output, with a consistent total magnitude, regardless of the input magnitude. Notice that there is some slight perturbation due to rounding and some approximations with the fixed point square root algorithm. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e5a1945", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/lava_va/Tutorial04-Creating_network_motifs.ipynb b/tutorials/lava_va/Tutorial04-Creating_network_motifs.ipynb new file mode 100644 index 000000000..087759fc4 --- /dev/null +++ b/tutorials/lava_va/Tutorial04-Creating_network_motifs.ipynb @@ -0,0 +1,293 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b420cc24", + "metadata": {}, + "source": [ + "*Copyright (C) 2022-23 Intel Corporation*
\n", + "*SPDX-License-Identifier: BSD-3-Clause*
\n", + "*See: https://spdx.org/licenses/*\n", + "\n", + "---\n", + "\n", + "# Tutorial: Creating network motifs\n", + "\n", + "**Motivation:** In this tutorial, we will provide a walkthrough on how to create custom network motifs with Lava-VA. The Lava-VA Network is a recursive hierarchical container for creating reusable components. Custom motifs can be created with basic python syntax and links to standard components of the Lava-VA Network.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "72b82564", + "metadata": {}, + "outputs": [], + "source": [ + "from pylab import *" + ] + }, + { + "cell_type": "markdown", + "id": "41f00cf8", + "metadata": {}, + "source": [ + "First, we will import the objects into the lv namespace and connect to Loihi 2." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4d85a200", + "metadata": {}, + "outputs": [], + "source": [ + "import lava.frameworks.loihi2 as lv" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "c7047153", + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.sparse import csr_matrix" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2a68a562", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running on Loihi 2\n" + ] + } + ], + "source": [ + "from lava.utils import loihi\n", + "\n", + "loihi.use_slurm_host(loihi_gen=loihi.ChipGeneration.N3B3)\n", + "use_loihi2 = loihi.is_installed()\n", + "#use_loihi2 = False\n", + "\n", + "if use_loihi2:\n", + " run_cfg = lv.Loihi2HwCfg()\n", + " print(\"Running on Loihi 2\")\n", + "else:\n", + " run_cfg = lv.Loihi2SimCfg(select_tag='fixed_pt')\n", + " print(\"Loihi2 compiler is not available in this system. \"\n", + " \"This tutorial will execute on CPU backend.\")" + ] + }, + { + "cell_type": "markdown", + "id": "8f9ad5c7", + "metadata": {}, + "source": [ + "Our goal for this tutorial is to create a simple memory buffer network. This is also often called a shift register in standard digital electronics. \n", + "\n", + "In particular, our design will consist of a population of GradedVec neurons, which transmit graded spike values. We want to connect the population with a recurrent matrix, so that each value is transferred to the neighboring neuron on the next timestep. \n", + "\n", + "Further, we want to incorporate the operator overloading. To do so we can inherit from the AlgebraicVector class that includes the overloading function. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4b250b2d", + "metadata": {}, + "outputs": [], + "source": [ + "from lava.networks.network import AlgebraicVector\n", + "\n", + "class MemoryBuffer(AlgebraicVector):\n", + " def __init__(self, shape):\n", + " self.shape = shape\n", + " \n", + " # Create the weight matrix \n", + " rec_weights = np.roll(np.eye(self.shape[0]), 1, axis=0)\n", + " \n", + " # Instantiate the core Network objects\n", + " self.main = lv.GradedVec(shape=shape, vth=1)\n", + " self.buf_weights = lv.GradedSparse(weights=rec_weights)\n", + " \n", + " # Create the network motif by connecting the recurrent \n", + " # weights to the neural population\n", + " self.main << self.buf_weights @ self.main\n", + "\n", + " # Connect the standard ports\n", + " self.in_port = self.main.in_port\n", + " self.out_port = self.main.out_port\n", + " \n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "cf9bc778", + "metadata": {}, + "source": [ + "Now that we've created our custom network motif, we can use it in a simulation." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "521eb200", + "metadata": {}, + "outputs": [], + "source": [ + "num_steps = 20\n", + "mem_buffer_size = (50,)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0881a1ef", + "metadata": {}, + "outputs": [], + "source": [ + "inp_data = np.zeros((1, num_steps))\n", + "\n", + "inp_data[:, 1] = 2\n", + "inp_data[:, 3] = 4\n", + "inp_data[:, 5] = 8\n", + "inp_data[:, 7] = 16\n", + "inp_data[:, 9] = 32\n", + "inp_data[:, 11] = 64\n", + "\n", + "in_weights = np.zeros((mem_buffer_size[0], 1))\n", + "in_weights[0] = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "51d9a920", + "metadata": {}, + "outputs": [], + "source": [ + "invec = lv.InputVec(inp_data, loihi2=use_loihi2)\n", + "\n", + "in_out_syn = lv.GradedDense(weights=in_weights)\n", + "\n", + "memvec = MemoryBuffer(shape=mem_buffer_size)\n", + "\n", + "out_monitor = lv.OutputVec(shape=mem_buffer_size, buffer=num_steps, loihi2=use_loihi2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f861a87f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "memvec << in_out_syn @ invec\n", + "out_monitor << memvec" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "fcc17544", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " memvec.run(condition=lv.RunSteps(num_steps=num_steps), \n", + " run_cfg=run_cfg)\n", + " out_spike_data = out_monitor.get_data()\n", + "finally:\n", + " memvec.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "ac427ab4", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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8wlUW1urM844Q/v27Zvwf9+eDx+lpaVatGiRtm7daj0WiUS0detWtbS05PHKCkNzc7Pq6+vj7n9fX5927NjB/U+DYRi65ZZbtHnzZr344otqbm6Oe37RokUqKSmJu9979uzRgQMHuN9ZEolEFAwGudcT4PLLL9dbb72l3bt3W18XXnihrrvuOuvv3POJc+zYMX3wwQdqaGiY+H/fGbesngQ2btxoBAIBY8OGDca7775r3HTTTUZtba3R1dWV70vzhP7+fuONN94w3njjDUOScf/99xtvvPGG8eGHHxqGYRhr1641amtrjWeeecZ48803jauuuspobm42Tpw4kecrP/ncfPPNRk1NjfHyyy8bhw8ftr6OHz9uveZ73/ueMWfOHOPFF180du3aZbS0tBgtLS15vOqT1w9+8AOjo6PD2L9/v/Hmm28aP/jBDwyfz2f89re/NQyDe50L9t0uhsE9z6a/+Zu/MV5++WVj//79xu9+9zujtbXVmDFjhnHkyBHDMCb2XhdE+DAMw/inf/onY86cOUZpaalx0UUXGdu3b8/3JXnGSy+9ZEga87VixQrDMKLbbe+8806jrq7OCAQCxuWXX27s2bMnvxd9kkp0nyUZ69evt15z4sQJ46/+6q+MqVOnGlOmTDG+9rWvGYcPH87fRZ/EvvOd7xhz5841SktLjZkzZxqXX365FTwMg3udC6PDB/c8e6699lqjoaHBKC0tNU455RTj2muvNfbt22c9P5H32mcYhpF5/QQAAMAZz/d8AACAyYXwAQAAcorwAQAAcorwAQAAcorwAQAAcorwAQAAcorwAQAAcorwAQAAcorwAQAAcorwAQAAcorwAQAAcorwAQAAcur/B57V7ElhMu6FAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot(out_spike_data[:, -1])\n" + ] + }, + { + "cell_type": "markdown", + "id": "92b21619", + "metadata": {}, + "source": [ + "The above network shows the last timestep of the memory buffer in the simulation. Here, we turned a temporal pattern into a spatial pattern using a simple permutation motif. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55b4c89d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}