From af35d6d23ec1c415d52e158dc3ee3ab8457dd248 Mon Sep 17 00:00:00 2001 From: "Xu, He" Date: Mon, 19 Jun 2023 07:31:47 +0000 Subject: [PATCH] Merge latest main to cpp_msglib Signed-off-by: Xu, He --- .github/ISSUE_TEMPLATE.md | 20 +- .github/ISSUE_TEMPLATE/bug_report.md | 10 +- .github/ISSUE_TEMPLATE/feature_request.md | 6 +- .github/PULL_REQUEST_TEMPLATE.md | 32 +- .github/workflows/cd.yml | 4 +- .github/workflows/ci.yml | 15 +- .../workflows/codacy_coverage_reporter.yml | 29 + README.md | 34 +- RELEASE.md | 106 +- poetry.lock | 2012 ++++++++--------- pyproject.toml | 16 +- .../compiler/builders/channel_builder.py | 1 - .../magma/compiler/builders/interfaces.py | 2 - .../magma/compiler/builders/py_builder.py | 7 + src/lava/magma/compiler/channel_map.py | 5 +- src/lava/magma/compiler/compiler.py | 2 +- src/lava/magma/compiler/compiler_graphs.py | 1 - src/lava/magma/compiler/mapper.py | 3 +- src/lava/magma/compiler/node.py | 5 +- .../subcompilers/channel_builders_factory.py | 4 +- .../magma/compiler/subcompilers/interfaces.py | 2 - src/lava/magma/compiler/utils.py | 2 - src/lava/magma/compiler/var_model.py | 1 + src/lava/magma/core/learning/constants.py | 11 +- .../magma/core/learning/symbolic_equation.py | 12 +- src/lava/magma/core/learning/utils.py | 1 - src/lava/magma/core/model/interfaces.py | 1 - src/lava/magma/core/model/py/connection.py | 150 +- src/lava/magma/core/model/py/model.py | 48 +- src/lava/magma/core/model/py/ports.py | 26 +- src/lava/magma/core/process/ports/ports.py | 45 +- .../magma/core/process/ports/reduce_ops.py | 4 - src/lava/magma/core/process/process.py | 46 +- src/lava/magma/core/process/variable.py | 26 +- src/lava/magma/core/resources.py | 18 - src/lava/magma/core/run_configs.py | 47 +- .../runtime/message_infrastructure/factory.py | 5 +- .../message_infrastructure_interface.py | 15 +- .../runtime/message_infrastructure/nx.py | 4 - .../message_infrastructure/pypychannel.py | 27 +- src/lava/magma/runtime/mgmt_token_enums.py | 6 +- src/lava/magma/runtime/runtime.py | 12 +- .../channel_broker/channel_broker.py | 1 - .../runtime_services/runtime_service.py | 55 +- src/lava/proc/conv/utils.py | 20 +- src/lava/proc/dense/models.py | 57 +- src/lava/proc/dense/process.py | 5 +- src/lava/proc/io/encoder.py | 1 - src/lava/proc/lif/models.py | 68 +- src/lava/proc/lif/process.py | 79 +- src/lava/proc/monitor/process.py | 33 +- src/lava/proc/sparse/models.py | 372 +++ src/lava/proc/sparse/process.py | 277 +++ src/lava/proc/spiker/models.py | 2 +- src/lava/utils/dataloader/mnist.py | 3 +- src/lava/utils/sparse.py | 32 + src/lava/utils/weightutils.py | 67 +- .../subcompilers/py/test_pyproc_compiler.py | 3 +- .../test_channel_builders_factory.py | 13 +- tests/lava/magma/compiler/test_channel_map.py | 1 - tests/lava/magma/compiler/test_compiler.py | 4 - tests/lava/magma/compiler/test_node.py | 2 - .../magma/core/learning/test_learning_rule.py | 19 +- tests/lava/magma/core/learning/test_random.py | 1 - tests/lava/magma/core/model/py/test_model.py | 11 +- .../lava/magma/core/model/test_decorators.py | 18 +- .../magma/core/process/ports/test_ports.py | 21 +- .../magma/core/process/test_lif_dense_lif.py | 16 +- tests/lava/magma/core/process/test_process.py | 59 +- .../lava/magma/runtime/test_async_protocol.py | 8 +- .../runtime/test_get_set_non_determinism.py | 2 +- .../runtime/test_loihi_with_async_protocol.py | 9 +- tests/lava/proc/conv/test_utils.py | 8 +- tests/lava/proc/dense/test_learning.py | 11 +- tests/lava/proc/dense/test_models.py | 2 +- tests/lava/proc/io/test_dataloader.py | 12 +- tests/lava/proc/io/test_source_sink.py | 12 +- tests/lava/proc/lif/test_models.py | 44 +- tests/lava/proc/rf/test_models.py | 44 +- tests/lava/proc/rf_iz/test_models.py | 22 +- tests/lava/proc/sdn/test_models.py | 56 +- tests/lava/proc/sparse/__init__.py | 0 tests/lava/proc/sparse/test_models.py | 1449 ++++++++++++ tests/lava/proc/sparse/test_process.py | 134 ++ tests/lava/proc/spiker/test_models.py | 4 +- tests/lava/test_utils/utils.py | 10 +- tests/lava/tutorials/test_tutorials.py | 5 +- tests/lava/utils/test_plots.py | 10 +- .../in_depth/three_factor_learning/utils.py | 34 +- 89 files changed, 4183 insertions(+), 1756 deletions(-) create mode 100644 .github/workflows/codacy_coverage_reporter.yml create mode 100644 src/lava/proc/sparse/models.py create mode 100644 src/lava/proc/sparse/process.py create mode 100644 src/lava/utils/sparse.py create mode 100644 tests/lava/proc/sparse/__init__.py create mode 100644 tests/lava/proc/sparse/test_models.py create mode 100644 tests/lava/proc/sparse/test_process.py diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4dbe39eb2..d96b923fc 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -17,19 +17,19 @@ Objective of issue: **Lava version:** -- [ ] **0.6.0** (feature release) -- [ ] **0.5.1** (bug fixes) -- [x] **0.5.0** (current version) -- [ ] **0.4.1** -- [ ] **0.4.0** -- [ ] **0.3.0** -- [ ] **0.1.2** +- [ ] **0.6.0** (feature release) +- [ ] **0.5.1** (bug fixes) +- [x] **0.5.0** (current version) +- [ ] **0.4.1** +- [ ] **0.4.0** +- [ ] **0.3.0** +- [ ] **0.1.2** **I'm submitting a ...** -- [ ] bug report -- [ ] feature request -- [ ] documentation request +- [ ] bug report +- [ ] feature request +- [ ] documentation request diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ff3259a2e..49f097a3a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -22,12 +22,12 @@ A clear and concise description of what the bug is. **To reproduce current behavior** Steps to reproduce the behavior: -1. When I run this code (add code or minimum test case) ... +1. When I run this code (add code or minimum test case) ... ```python def my_code(): pass ``` -2. I get this error ... +2. I get this error ... ``` Error... ``` @@ -39,9 +39,9 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. Remove section otherwise. **Environment (please complete the following information):** - - Device: [e.g. Laptop, Intel cloud] - - OS: [e.g. Linux] - - Lava version [e.g. 0.6.1] +- Device: [e.g. Laptop, Intel cloud] +- OS: [e.g. Linux] +- Lava version [e.g. 0.6.1] **Additional context** Add any other context about the problem here. Remove section otherwise. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 083147669..a0b34ba9d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -11,8 +11,8 @@ assignees: '' As a user, I want to [capability] to [benefit]. ### Conditions of satisfaction -- An optional list of conditions that have to be fulfilled for this feature to be complete. -- For example: "Users can add both individual items and lists as parameters." +- An optional list of conditions that have to be fulfilled for this feature to be complete. +- For example: "Users can add both individual items and lists as parameters." ### Acceptance tests -- An optional list of tests that should be written to automatically test the new feature. +- An optional list of tests that should be written to automatically test the new feature. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bc820529f..4eb543f72 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -12,13 +12,13 @@ Objective of pull request: ## Pull request checklist Your PR fulfills the following requirements: -- [ ] [Issue](https://github.com/lava-nc/lava/issues) created that explains the change and why it's needed -- [ ] Tests are part of the PR (for bug fixes / features) -- [ ] [Docs](https://github.com/lava-nc/docs) reviewed and added / updated if needed (for bug fixes / features) -- [ ] PR conforms to [Coding Conventions](https://lava-nc.org/developer_guide.html#coding-conventions) -- [ ] [PR applys BSD 3-clause or LGPL2.1+ Licenses](https://lava-nc.org/developer_guide.html#add-a-license) to all code files -- [ ] Lint (`flakeheaven lint src/lava tests/`) and (`bandit -r src/lava/.`) pass locally -- [ ] Build tests (`pytest`) passes locally +- [ ] [Issue](https://github.com/lava-nc/lava/issues) created that explains the change and why it's needed +- [ ] Tests are part of the PR (for bug fixes / features) +- [ ] [Docs](https://github.com/lava-nc/docs) reviewed and added / updated if needed (for bug fixes / features) +- [ ] PR conforms to [Coding Conventions](https://lava-nc.org/developer_guide.html#coding-conventions) +- [ ] [PR applys BSD 3-clause or LGPL2.1+ Licenses](https://lava-nc.org/developer_guide.html#add-a-license) to all code files +- [ ] Lint (`flakeheaven lint src/lava tests/`) and (`bandit -r src/lava/.`) pass locally +- [ ] Build tests (`pytest`) passes locally ## Pull request type @@ -30,13 +30,13 @@ Your PR fulfills the following requirements: Please check your PR type: -- [ ] Bugfix -- [ ] Feature -- [ ] Code style update (formatting, renaming) -- [ ] Refactoring (no functional changes, no api changes) -- [ ] Build related changes -- [ ] Documentation changes -- [ ] Other (please describe): +- [ ] Bugfix +- [ ] Feature +- [ ] Code style update (formatting, renaming) +- [ ] Refactoring (no functional changes, no api changes) +- [ ] Build related changes +- [ ] Documentation changes +- [ ] Other (please describe): ## What is the current behavior? @@ -50,8 +50,8 @@ Please check your PR type: ## Does this introduce a breaking change? -- [ ] Yes -- [ ] No +- [ ] Yes +- [ ] No diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 6e38a44bc..a66ae8955 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -99,7 +99,7 @@ jobs: python3.9 -m venv artifact-unittest source artifact-unittest/bin/activate pip install -U pip - pip install nbconvert>=7.2.2 pytest>=7.2.0 matplotlib>=3.5.1 ipykernel>=6.15.0 nbformat>=5.3.0 nbconvert>=7.2.2 + pip install "nbconvert>=7.2.10,<7.3" pytest>=7.2.0 matplotlib>=3.5.1 ipykernel>=6.15.0 nbformat>=5.3.0 artifact=$(ls | grep lava | grep tar) pip install --no-input $artifact tar -xvf $artifact @@ -118,7 +118,7 @@ jobs: python3.9 -m venv artifact-unittest source artifact-unittest/bin/activate pip install -U pip - pip install nbconvert>=7.2.2 pytest>=7.2.0 matplotlib>=3.5.1 ipykernel>=6.15.0 nbformat>=5.3.0 nbconvert>=7.2.2 + pip install "nbconvert>=7.2.10,<7.3" pytest>=7.2.0 matplotlib>=3.5.1 ipykernel>=6.15.0 nbformat>=5.3.0 artifact=$(ls | grep lava | grep whl) pip install --no-input $artifact # Change $artifact to tar.gz diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ab7341eb..9d4ea435c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,8 +81,19 @@ jobs: run: | poetry run git lfs fetch poetry run git lfs pull - # poetry run pytest - poetry run python -m unittest discover -s tests/ -t . -vv + poetry run coverage run -m unittest discover -s tests/ -t . -vv + + - name: Generate coverage report + if: runner.os == 'Linux' + run: poetry run coverage xml + + - name: Archive coverage report + if: runner.os == 'Linux' + uses: actions/upload-artifact@v3 + with: + name: coverage + path: coverage.xml + retention-days: 30 msg-infr-unit-tests: name: Message Infrastructure Unit Test diff --git a/.github/workflows/codacy_coverage_reporter.yml b/.github/workflows/codacy_coverage_reporter.yml new file mode 100644 index 000000000..a6826c9c5 --- /dev/null +++ b/.github/workflows/codacy_coverage_reporter.yml @@ -0,0 +1,29 @@ +name: Codacy Coverage Reporter + +on: + workflow_run: + workflows: ["Run CI"] + types: [completed] + branches: [main] + workflow_dispatch: + +jobs: + codacy-coverage-reporter: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }} + name: codacy-coverage-reporter + steps: + - name: Download artifact + uses: dawidd6/action-download-artifact@v2 + with: + workflow: ci.yml + workflow_conclusion: "success" + branch: main + event: push + name: coverage + + - name: Run codacy-coverage-reporter + uses: codacy/codacy-coverage-reporter-action@v1 + with: + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + coverage-reports: coverage.xml diff --git a/README.md b/README.md index b1b1ef9c5..c8a740275 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,11 @@ A Software Framework for Neuromorphic Computing

+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/40792fa7db054279bdf7532e36f0cfab)](https://app.codacy.com/gh/lava-nc/lava/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) +[![Codacy Badge](https://app.codacy.com/project/badge/Coverage/40792fa7db054279bdf7532e36f0cfab)](https://app.codacy.com/gh/lava-nc/lava/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage) + +If you like lava and want to support it, the easiest way is to star our repo (click star in the upper right corner). + # Overview Lava is an open source SW framework to develop applications for @@ -35,22 +40,13 @@ supporting architectures like Intel Loihi may remain proprietary to Intel and will be shared as extensions to eligible users. >### Lava extension for Intel's Loihi ->The Lava extension for Loihi is available for members of the Intel -Neuromorphic Research Community (INRC). The extension enables execution of -Lava on Intel's Loihi hardware platform. +>The Lava extension for Loihi is available for members of the Intel Neuromorphic Research Community (INRC). The extension enables execution of Lava on Intel's Loihi hardware platform. > ->Developers interested in using Lava with Loihi systems need to join the -INRC. Loihi 1 and 2 research systems are currently not available -commercially. Once a member of the INRC, developers will gain access to -cloud-hosted Loihi systems or may be able to obtain physical Loihi systems on a -loan basis. +>Developers interested in using Lava with Loihi systems need to join the INRC. Loihi 1 and 2 research systems are currently not available commercially. Once a member of the INRC, developers will gain access to cloud-hosted Loihi systems or may be able to obtain physical Loihi systems on a loan basis. > ->To join the INRC, visit [http://neuromorphic.intel.com](http://neuromorphic.intel.com) -or email at [inrc_interest@intel.com](mailto:inrc_interest@intel.com). +>To join the INRC, visit [http://neuromorphic.intel.com](http://neuromorphic.intel.com) or email at [inrc_interest@intel.com](mailto:inrc_interest@intel.com). > -> If you are already a member of the INRC, please read how to [get - started with the Lava extension for Loihi.](https://intel-ncl.atlassian.net/wiki/spaces/NAP/pages/1785856001/Get+started+with+the+Lava+extension+for+Loihi) -> This page is **only** accessible to members of the INRC. +> If you are already a member of the INRC, please read how to [get started with the Lava extension for Loihi](https://intel-ncl.atlassian.net/wiki/spaces/NAP/pages/1785856001/Get+started+with+the+Lava+extension+for+Loihi). This page is **only** accessible to members of the INRC. # Getting started @@ -70,7 +66,7 @@ will need to install the `poetry` Python package. Open a **python 3** terminal and run based on the OS you are on: -### [Linux/MacOS] +### Linux/MacOS ```bash cd $HOME @@ -87,7 +83,7 @@ pytest ## See FAQ for more info: https://github.com/lava-nc/lava/wiki/Frequently-Asked-Questions-(FAQ)#install ``` -### [Windows] +### Windows ```powershell # Commands using PowerShell @@ -140,7 +136,7 @@ Required test coverage of 85.0% reached. Total coverage: 88.81% ``` -## [Alternative] Installing Lava via Conda +## Alternative: Installing Lava via Conda If you use the Conda package manager, you can simply install the Lava package via: @@ -158,7 +154,7 @@ conda install -n lava -c intel numpy scipy conda install -n lava -c conda-forge lava --freeze-installed ``` -## [Alternative] Installing Lava from binaries +## Alternative: Installing Lava from binaries If you only need to install Lava as a user in your python environment, we will publish Lava releases via @@ -167,7 +163,7 @@ the package and install it. Open a Python terminal and run: -### [Windows/MacOS/Linux] +### Windows/MacOS/Linux ```bash python -m venv .venv @@ -203,7 +199,7 @@ bandit -r src/lava/. bandit -r src/lava/. --format custom --msg-template '{abspath}:{line}: {test_id}[bandit]: {severity}: {msg}' ``` ## -> Refer to the tutorials directory for in-depth as well as end-to-end tutorials on how to write Lava Processes, connect them, and execute the code. +>Refer to the tutorials directory for in-depth as well as end-to-end tutorials on how to write Lava Processes, connect them, and execute the code. # Stay in touch diff --git a/RELEASE.md b/RELEASE.md index 0493bdc4e..1852313be 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -4,79 +4,79 @@ While this release offers few high-level application examples, Lava v0.4.0 provi ## New Features and Improvements Features marked with * are available as part of the Loihi 2 extension. -- *Extended Process library including new ProcessModels and additional improvements: - - LIF, Sigma-Delta, and Dense Processes execute on Loihi NeuroCores. - - Prototype Convolutional Process added. - - Sending and receiving spikes to NeuroCores via embedded processes that can be programmed in C with examples included. - - All Lava Processes now list all constructor arguments explicitly with type annotations. -- *Added high-level API to develop custom ProcessModels that use Loihi 2 features: - - Loihi NeuroCores can be programmed in Python by allocating neural network resources like Axons, Synapses or Neurons. In particular, Loihi 2 NeuroCore Neurons can be configured by writing highly flexible assembly programs. - - Loihi embedded processors can be programmed in C. But unlike the prior NxSDK, no knowledge of low-level registers details is required anymore. Instead, the C API mirrors the high-level Python API to interact with other processes via channels. -- Compiler and Runtime support for Loihi 2: - - General redesign of Compiler and Runtime architecture to support compilation of Processes that execute across a heterogenous backend of different compute resources. CPU and Loihi are supported via separate sub compilers. - - *The Loihi NeuroCore sub compiler automatically distributes neural network resources across multiple cores. - - *The Runtime supports direct channel-based communication between Processes running on Loihi NeuroCores, embedded CPUs or host CPUs written in Python or C. Of all combinations, only Python<->C and C<->NeuroCore are currently supported. - - *Added support to access Process Variables on Loihi NeuroCores at runtime via Var.set and Var.get(). -- New tutorials and improved class and method docstrings explain how new Lava features can be used such as *NeuroCore and *embedded processor programming. -- An extended suite of unit tests and new *integration tests validate the correctness of the Lava framework. +- *Extended Process library including new ProcessModels and additional improvements: + - LIF, Sigma-Delta, and Dense Processes execute on Loihi NeuroCores. + - Prototype Convolutional Process added. + - Sending and receiving spikes to NeuroCores via embedded processes that can be programmed in C with examples included. + - All Lava Processes now list all constructor arguments explicitly with type annotations. +- *Added high-level API to develop custom ProcessModels that use Loihi 2 features: + - Loihi NeuroCores can be programmed in Python by allocating neural network resources like Axons, Synapses or Neurons. In particular, Loihi 2 NeuroCore Neurons can be configured by writing highly flexible assembly programs. + - Loihi embedded processors can be programmed in C. But unlike the prior NxSDK, no knowledge of low-level registers details is required anymore. Instead, the C API mirrors the high-level Python API to interact with other processes via channels. +- Compiler and Runtime support for Loihi 2: + - General redesign of Compiler and Runtime architecture to support compilation of Processes that execute across a heterogenous backend of different compute resources. CPU and Loihi are supported via separate sub compilers. + - *The Loihi NeuroCore sub compiler automatically distributes neural network resources across multiple cores. + - *The Runtime supports direct channel-based communication between Processes running on Loihi NeuroCores, embedded CPUs or host CPUs written in Python or C. Of all combinations, only Python<->C and C<->NeuroCore are currently supported. + - *Added support to access Process Variables on Loihi NeuroCores at runtime via Var.set and Var.get(). +- New tutorials and improved class and method docstrings explain how new Lava features can be used such as *NeuroCore and *embedded processor programming. +- An extended suite of unit tests and new *integration tests validate the correctness of the Lava framework. ## Bug Fixes and Other Changes -- Support for virtual ports on multiple incoming connections (Python Processes only) (Issue [#223](https://github.com/lava-nc/lava/issues/223), PR [#224](https://github.com/lava-nc/lava/pull/224)) -- Added conda install instructions (PR [#225](https://github.com/lava-nc/lava/pull/225)) -- Var.set/get() works when RunContinuous RunMode is used (Issue [#255](https://github.com/lava-nc/lava/issues/255), PR [#256](https://github.com/lava-nc/lava/pull/256)) -- Successful execution of tutorials now covered by unit tests (Issue [#243](https://github.com/lava-nc/lava/issues/243), PR [#244](https://github.com/lava-nc/lava/pull/244)) -- Fixed PYTHONPATH in tutorial_01 (Issue [#45](https://github.com/lava-nc/lava/issues/45), PR [#239](https://github.com/lava-nc/lava/pull/239)) -- Fixed output of tutorial_07 (Issue [#249](https://github.com/lava-nc/lava/issues/249), PR [#253](https://github.com/lava-nc/lava/pull/253)) +- Support for virtual ports on multiple incoming connections (Python Processes only) (Issue [#223](https://github.com/lava-nc/lava/issues/223), PR [#224](https://github.com/lava-nc/lava/pull/224)) +- Added conda install instructions (PR [#225](https://github.com/lava-nc/lava/pull/225)) +- Var.set/get() works when RunContinuous RunMode is used (Issue [#255](https://github.com/lava-nc/lava/issues/255), PR [#256](https://github.com/lava-nc/lava/pull/256)) +- Successful execution of tutorials now covered by unit tests (Issue [#243](https://github.com/lava-nc/lava/issues/243), PR [#244](https://github.com/lava-nc/lava/pull/244)) +- Fixed PYTHONPATH in tutorial_01 (Issue [#45](https://github.com/lava-nc/lava/issues/45), PR [#239](https://github.com/lava-nc/lava/pull/239)) +- Fixed output of tutorial_07 (Issue [#249](https://github.com/lava-nc/lava/issues/249), PR [#253](https://github.com/lava-nc/lava/pull/253)) ## Breaking Changes -- Process constructors for standard library processes now require explicit keyword/value pairs and do not accept arbitrary input arguments via **kwargs anymore. This might break some workloads. -- use_graded_spike kwarg has been changed to num_message_bits for all the built-in processes. -- shape kwarg has been removed from Dense process. It is automatically inferred from the weight parameter’s shape. -- Conv Process has additional arguments weight_exp and num_weight_bits that are relevant for fixed-point implementations. -- The sign_mode argument in the Dense Process is now an enum rather than an integer. -- New parameters u and v in the LIF Process enable setting initial values for current and voltage. -- The bias parameter in the LIF Process has been renamed to bias_mant. +- Process constructors for standard library processes now require explicit keyword/value pairs and do not accept arbitrary input arguments via **kwargs anymore. This might break some workloads. +- use_graded_spike kwarg has been changed to num_message_bits for all the built-in processes. +- shape kwarg has been removed from Dense process. It is automatically inferred from the weight parameter’s shape. +- Conv Process has additional arguments weight_exp and num_weight_bits that are relevant for fixed-point implementations. +- The sign_mode argument in the Dense Process is now an enum rather than an integer. +- New parameters u and v in the LIF Process enable setting initial values for current and voltage. +- The bias parameter in the LIF Process has been renamed to bias_mant. ## Known Issues -- Lava does currently not support on-chip learning, Loihi 1 and a variety of connectivity compression features such as convolutional encoding. -- All Processes in a network must currently be connected via channels. Running unconnected Processes using NcProcessModels in parallel currently gives incorrect results. -- Only one instance of a Process targeting an embedded processor (using CProcessModel) can currently be created. Creating multiple instances in a network, results in an error. As a workaround, the behavior of multiple Processes can be fused into a single CProcessModel. -- Direct channel connections between Processes using a PyProcessModel and NcProcessModel are not supported. -- In the scenario that InputAxons are duplicated across multiple cores and users expect to inject spikes based on the declared port size, then the current implementation leads to buffer overflows and memory corruption. -- Channel communication between PyProcessModels is slow. -- The Lava Compiler is still inefficient and in need of improvement to performance and memory utilization. -- Virtual ports are only supported between Processes using PyProcModels, but not between Processes when CProcModels or NcProcModels are involved. In addition, VirtualPorts do not support concatenation yet. -- Joining and forking of virtual ports is not supported. -- The Monitor Process does currently only support probing of a single Var per Process implemented via a PyProcessModel. The Monitor Process does currently not support probing of Vars mapped to NeuroCores. -- Despite new docstrings, type annotations, and parameter descriptions to most of the public user-facing API, some parts of the code still have limited documentation and are missing type annotations. +- Lava does currently not support on-chip learning, Loihi 1 and a variety of connectivity compression features such as convolutional encoding. +- All Processes in a network must currently be connected via channels. Running unconnected Processes using NcProcessModels in parallel currently gives incorrect results. +- Only one instance of a Process targeting an embedded processor (using CProcessModel) can currently be created. Creating multiple instances in a network, results in an error. As a workaround, the behavior of multiple Processes can be fused into a single CProcessModel. +- Direct channel connections between Processes using a PyProcessModel and NcProcessModel are not supported. +- In the scenario that InputAxons are duplicated across multiple cores and users expect to inject spikes based on the declared port size, then the current implementation leads to buffer overflows and memory corruption. +- Channel communication between PyProcessModels is slow. +- The Lava Compiler is still inefficient and in need of improvement to performance and memory utilization. +- Virtual ports are only supported between Processes using PyProcModels, but not between Processes when CProcModels or NcProcModels are involved. In addition, VirtualPorts do not support concatenation yet. +- Joining and forking of virtual ports is not supported. +- The Monitor Process does currently only support probing of a single Var per Process implemented via a PyProcessModel. The Monitor Process does currently not support probing of Vars mapped to NeuroCores. +- Despite new docstrings, type annotations, and parameter descriptions to most of the public user-facing API, some parts of the code still have limited documentation and are missing type annotations. ## What's Changed -* Virtual ports on multiple incoming connections by @mathisrichter in https://github.com/lava-nc/lava/pull/224 -* Add conda install to README by @Tobias-Fischer in https://github.com/lava-nc/lava/pull/225 -* PYTHONPATH fix in tutorial by @jlubo in https://github.com/lava-nc/lava/pull/239 -* Fix tutorial04_execution.ipynb by @mgkwill in https://github.com/lava-nc/lava/pull/241 -* Tutorial tests by @mgkwill in https://github.com/lava-nc/lava/pull/244 -* Update README.md remove vlab instructions by @mgkwill in https://github.com/lava-nc/lava/pull/248 -* Tutorial bug fix by @PhilippPlank in https://github.com/lava-nc/lava/pull/253 -* Fix get set var by @PhilippPlank in https://github.com/lava-nc/lava/pull/256 -* Update runtime_service.py by @PhilippPlank in https://github.com/lava-nc/lava/pull/258 -* Release/v0.4.0 by @mgkwill in https://github.com/lava-nc/lava/pull/265 +* Virtual ports on multiple incoming connections by @mathisrichter in https://github.com/lava-nc/lava/pull/224 +* Add conda install to README by @Tobias-Fischer in https://github.com/lava-nc/lava/pull/225 +* PYTHONPATH fix in tutorial by @jlubo in https://github.com/lava-nc/lava/pull/239 +* Fix tutorial04_execution.ipynb by @mgkwill in https://github.com/lava-nc/lava/pull/241 +* Tutorial tests by @mgkwill in https://github.com/lava-nc/lava/pull/244 +* Update README.md remove vlab instructions by @mgkwill in https://github.com/lava-nc/lava/pull/248 +* Tutorial bug fix by @PhilippPlank in https://github.com/lava-nc/lava/pull/253 +* Fix get set var by @PhilippPlank in https://github.com/lava-nc/lava/pull/256 +* Update runtime_service.py by @PhilippPlank in https://github.com/lava-nc/lava/pull/258 +* Release/v0.4.0 by @mgkwill in https://github.com/lava-nc/lava/pull/265 ## Thanks to our Contributors -- Intel Corporation: All contributing members of the Intel Neuromorphic Computing Lab +- Intel Corporation: All contributing members of the Intel Neuromorphic Computing Lab ### Open-source community: -- [Tobias-Fischer](https://github.com/Tobias-Fischer), Tobias Fischer -- [jlubo](https://github.com/jlubo), Jannik Luboeinski +- [Tobias-Fischer](https://github.com/Tobias-Fischer), Tobias Fischer +- [jlubo](https://github.com/jlubo), Jannik Luboeinski ## New Contributors -* @jlubo made their first contribution in https://github.com/lava-nc/lava/pull/239 +* @jlubo made their first contribution in https://github.com/lava-nc/lava/pull/239 **Full Changelog**: https://github.com/lava-nc/lava/compare/v0.3.0...v0.4.0 diff --git a/poetry.lock b/poetry.lock index b50a855c7..6b539eae6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "alabaster" version = "0.7.13" description = "A configurable sidebar-enabled Sphinx theme" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -16,7 +15,6 @@ files = [ name = "appnope" version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" -category = "dev" optional = false python-versions = "*" files = [ @@ -28,7 +26,6 @@ files = [ name = "argparse" version = "1.4.0" description = "Python command-line parsing library" -category = "dev" optional = false python-versions = "*" files = [ @@ -40,7 +37,6 @@ files = [ name = "asteval" version = "0.9.29" description = "Safe, minimalistic evaluator of python expression using ast module" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -58,7 +54,6 @@ test = ["coverage", "pytest", "pytest-cov"] name = "asttokens" version = "2.2.1" description = "Annotate AST trees with source code positions" -category = "dev" optional = false python-versions = "*" files = [ @@ -74,28 +69,26 @@ test = ["astroid", "pytest"] [[package]] name = "attrs" -version = "22.2.0" +version = "23.1.0" description = "Classes Without Boilerplate" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, ] [package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,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]"] [[package]] name = "autopep8" version = "1.6.0" description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" -category = "dev" optional = false python-versions = "*" files = [ @@ -109,24 +102,22 @@ toml = "*" [[package]] name = "babel" -version = "2.11.0" +version = "2.12.1" description = "Internationalization utilities" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"}, - {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"}, + {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, + {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, ] [package.dependencies] -pytz = ">=2015.7" +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" -category = "dev" optional = false python-versions = "*" files = [ @@ -138,7 +129,6 @@ files = [ name = "bandit" version = "1.7.4" description = "Security oriented static analyser for python code." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -159,14 +149,13 @@ yaml = ["PyYAML"] [[package]] name = "beautifulsoup4" -version = "4.11.2" +version = "4.12.2" description = "Screen-scraping library" -category = "dev" optional = false python-versions = ">=3.6.0" files = [ - {file = "beautifulsoup4-4.11.2-py3-none-any.whl", hash = "sha256:0e79446b10b3ecb499c1556f7e228a53e64a2bfcebd455f370d8927cb5b59e39"}, - {file = "beautifulsoup4-4.11.2.tar.gz", hash = "sha256:bc4bdda6717de5a2987436fb8d72f45dc90dd856bdfd512a1314ce90349a0106"}, + {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, + {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, ] [package.dependencies] @@ -180,7 +169,6 @@ lxml = ["lxml"] name = "bleach" version = "6.0.0" description = "An easy safelist-based HTML-sanitizing tool." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -195,16 +183,38 @@ webencodings = "*" [package.extras] css = ["tinycss2 (>=1.1.0,<1.2)"] +[[package]] +name = "build" +version = "0.10.0" +description = "A simple, correct Python build frontend" +optional = false +python-versions = ">= 3.7" +files = [ + {file = "build-0.10.0-py3-none-any.whl", hash = "sha256:af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171"}, + {file = "build-0.10.0.tar.gz", hash = "sha256:d5b71264afdb5951d6704482aac78de887c80691c52b88a9ad195983ca2c9269"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "os_name == \"nt\""} +packaging = ">=19.0" +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)"] +virtualenv = ["virtualenv (>=20.0.35)"] + [[package]] name = "cachecontrol" -version = "0.12.11" +version = "0.12.14" description = "httplib2 caching for requests" -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "CacheControl-0.12.11-py2.py3-none-any.whl", hash = "sha256:2c75d6a8938cb1933c75c50184549ad42728a27e9f6b92fd677c3151aa72555b"}, - {file = "CacheControl-0.12.11.tar.gz", hash = "sha256:a5b9fcc986b184db101aa280b42ecdcdfc524892596f606858e0b7a8b4d9e144"}, + {file = "CacheControl-0.12.14-py2.py3-none-any.whl", hash = "sha256:1c2939be362a70c4e5f02c6249462b3b7a24441e4f1ced5e9ef028172edf356a"}, + {file = "CacheControl-0.12.14.tar.gz", hash = "sha256:d1087f45781c0e00616479bfd282c78504371ca71da017b49df9f5365a95feba"}, ] [package.dependencies] @@ -218,21 +228,19 @@ redis = ["redis (>=2.10.5)"] [[package]] name = "certifi" -version = "2022.12.7" +version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, ] [[package]] name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." -category = "dev" optional = false python-versions = "*" files = [ @@ -307,107 +315,92 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.0.1" +version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, - {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, + {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, + {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, ] [[package]] name = "cleo" version = "2.0.1" description = "Cleo allows you to create beautiful and testable command-line interfaces." -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -423,7 +416,6 @@ rapidfuzz = ">=2.2.0,<3.0.0" name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -433,27 +425,27 @@ files = [ [[package]] name = "comm" -version = "0.1.2" +version = "0.1.3" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "comm-0.1.2-py3-none-any.whl", hash = "sha256:9f3abf3515112fa7c55a42a6a5ab358735c9dccc8b5910a9d8e3ef5998130666"}, - {file = "comm-0.1.2.tar.gz", hash = "sha256:3e2f5826578e683999b93716285b3b1f344f157bf75fa9ce0a797564e742f062"}, + {file = "comm-0.1.3-py3-none-any.whl", hash = "sha256:16613c6211e20223f215fc6d3b266a247b6e2641bf4e0a3ad34cb1aff2aa3f37"}, + {file = "comm-0.1.3.tar.gz", hash = "sha256:a61efa9daffcfbe66fd643ba966f846a624e4e6d6767eda9cf6e993aadaab93e"}, ] [package.dependencies] traitlets = ">=5.3" [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.0.7" description = "Python library for calculating contours of 2D quadrilateral grids" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -528,7 +520,6 @@ test-no-images = ["pytest"] name = "coverage" version = "6.5.0" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -594,7 +585,6 @@ toml = ["tomli"] name = "cpplint" version = "1.6.1" description = "Automated checker to ensure C++ files follow Google's style guide" -category = "dev" optional = false python-versions = "*" files = [ @@ -610,7 +600,6 @@ test = ["configparser (<=3.7.4)", "pyparsing (<3)", "pytest (>=4.6,<5.0)", "pyte name = "crashtest" version = "0.4.1" description = "Manage Python errors with ease" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -620,35 +609,30 @@ files = [ [[package]] name = "cryptography" -version = "39.0.1" +version = "41.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "cryptography-39.0.1-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:6687ef6d0a6497e2b58e7c5b852b53f62142cfa7cd1555795758934da363a965"}, - {file = "cryptography-39.0.1-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:706843b48f9a3f9b9911979761c91541e3d90db1ca905fd63fee540a217698bc"}, - {file = "cryptography-39.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:5d2d8b87a490bfcd407ed9d49093793d0f75198a35e6eb1a923ce1ee86c62b41"}, - {file = "cryptography-39.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e17b26de248c33f3acffb922748151d71827d6021d98c70e6c1a25ddd78505"}, - {file = "cryptography-39.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e124352fd3db36a9d4a21c1aa27fd5d051e621845cb87fb851c08f4f75ce8be6"}, - {file = "cryptography-39.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:5aa67414fcdfa22cf052e640cb5ddc461924a045cacf325cd164e65312d99502"}, - {file = "cryptography-39.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:35f7c7d015d474f4011e859e93e789c87d21f6f4880ebdc29896a60403328f1f"}, - {file = "cryptography-39.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f24077a3b5298a5a06a8e0536e3ea9ec60e4c7ac486755e5fb6e6ea9b3500106"}, - {file = "cryptography-39.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f0c64d1bd842ca2633e74a1a28033d139368ad959872533b1bab8c80e8240a0c"}, - {file = "cryptography-39.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0f8da300b5c8af9f98111ffd512910bc792b4c77392a9523624680f7956a99d4"}, - {file = "cryptography-39.0.1-cp36-abi3-win32.whl", hash = "sha256:fe913f20024eb2cb2f323e42a64bdf2911bb9738a15dba7d3cce48151034e3a8"}, - {file = "cryptography-39.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:ced4e447ae29ca194449a3f1ce132ded8fcab06971ef5f618605aacaa612beac"}, - {file = "cryptography-39.0.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:807ce09d4434881ca3a7594733669bd834f5b2c6d5c7e36f8c00f691887042ad"}, - {file = "cryptography-39.0.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c5caeb8188c24888c90b5108a441c106f7faa4c4c075a2bcae438c6e8ca73cef"}, - {file = "cryptography-39.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4789d1e3e257965e960232345002262ede4d094d1a19f4d3b52e48d4d8f3b885"}, - {file = "cryptography-39.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:96f1157a7c08b5b189b16b47bc9db2332269d6680a196341bf30046330d15388"}, - {file = "cryptography-39.0.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e422abdec8b5fa8462aa016786680720d78bdce7a30c652b7fadf83a4ba35336"}, - {file = "cryptography-39.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:b0afd054cd42f3d213bf82c629efb1ee5f22eba35bf0eec88ea9ea7304f511a2"}, - {file = "cryptography-39.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:6f8ba7f0328b79f08bdacc3e4e66fb4d7aab0c3584e0bd41328dce5262e26b2e"}, - {file = "cryptography-39.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ef8b72fa70b348724ff1218267e7f7375b8de4e8194d1636ee60510aae104cd0"}, - {file = "cryptography-39.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:aec5a6c9864be7df2240c382740fcf3b96928c46604eaa7f3091f58b878c0bb6"}, - {file = "cryptography-39.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fdd188c8a6ef8769f148f88f859884507b954cc64db6b52f66ef199bb9ad660a"}, - {file = "cryptography-39.0.1.tar.gz", hash = "sha256:d1f6198ee6d9148405e49887803907fe8962a23e6c6f83ea7d98f1c0de375695"}, + {file = "cryptography-41.0.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699"}, + {file = "cryptography-41.0.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a"}, + {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca"}, + {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43"}, + {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b"}, + {file = "cryptography-41.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3"}, + {file = "cryptography-41.0.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db"}, + {file = "cryptography-41.0.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31"}, + {file = "cryptography-41.0.1-cp37-abi3-win32.whl", hash = "sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5"}, + {file = "cryptography-41.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c"}, + {file = "cryptography-41.0.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb"}, + {file = "cryptography-41.0.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3"}, + {file = "cryptography-41.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039"}, + {file = "cryptography-41.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc"}, + {file = "cryptography-41.0.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485"}, + {file = "cryptography-41.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c"}, + {file = "cryptography-41.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a"}, + {file = "cryptography-41.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5"}, + {file = "cryptography-41.0.1.tar.gz", hash = "sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006"}, ] [package.dependencies] @@ -657,18 +641,17 @@ cffi = ">=1.12" [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)"] -pep8test = ["black", "check-manifest", "mypy", "ruff", "types-pytz", "types-requests"] -sdist = ["setuptools-rust (>=0.11.4)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-shard (>=0.1.2)", "pytest-subtests", "pytest-xdist", "pytz"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] -tox = ["tox"] [[package]] name = "cycler" version = "0.11.0" description = "Composable style cycles" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -680,7 +663,6 @@ files = [ name = "darglint" version = "1.8.1" description = "A utility for ensuring Google-style docstrings stay up to date with the source code." -category = "dev" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -690,36 +672,35 @@ files = [ [[package]] name = "debugpy" -version = "1.6.6" +version = "1.6.7" description = "An implementation of the Debug Adapter Protocol for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "debugpy-1.6.6-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:0ea1011e94416e90fb3598cc3ef5e08b0a4dd6ce6b9b33ccd436c1dffc8cd664"}, - {file = "debugpy-1.6.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dff595686178b0e75580c24d316aa45a8f4d56e2418063865c114eef651a982e"}, - {file = "debugpy-1.6.6-cp310-cp310-win32.whl", hash = "sha256:87755e173fcf2ec45f584bb9d61aa7686bb665d861b81faa366d59808bbd3494"}, - {file = "debugpy-1.6.6-cp310-cp310-win_amd64.whl", hash = "sha256:72687b62a54d9d9e3fb85e7a37ea67f0e803aaa31be700e61d2f3742a5683917"}, - {file = "debugpy-1.6.6-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:78739f77c58048ec006e2b3eb2e0cd5a06d5f48c915e2fc7911a337354508110"}, - {file = "debugpy-1.6.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23c29e40e39ad7d869d408ded414f6d46d82f8a93b5857ac3ac1e915893139ca"}, - {file = "debugpy-1.6.6-cp37-cp37m-win32.whl", hash = "sha256:7aa7e103610e5867d19a7d069e02e72eb2b3045b124d051cfd1538f1d8832d1b"}, - {file = "debugpy-1.6.6-cp37-cp37m-win_amd64.whl", hash = "sha256:f6383c29e796203a0bba74a250615ad262c4279d398e89d895a69d3069498305"}, - {file = "debugpy-1.6.6-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:23363e6d2a04d726bbc1400bd4e9898d54419b36b2cdf7020e3e215e1dcd0f8e"}, - {file = "debugpy-1.6.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b5d1b13d7c7bf5d7cf700e33c0b8ddb7baf030fcf502f76fc061ddd9405d16c"}, - {file = "debugpy-1.6.6-cp38-cp38-win32.whl", hash = "sha256:70ab53918fd907a3ade01909b3ed783287ede362c80c75f41e79596d5ccacd32"}, - {file = "debugpy-1.6.6-cp38-cp38-win_amd64.whl", hash = "sha256:c05349890804d846eca32ce0623ab66c06f8800db881af7a876dc073ac1c2225"}, - {file = "debugpy-1.6.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a771739902b1ae22a120dbbb6bd91b2cae6696c0e318b5007c5348519a4211c6"}, - {file = "debugpy-1.6.6-cp39-cp39-win32.whl", hash = "sha256:549ae0cb2d34fc09d1675f9b01942499751d174381b6082279cf19cdb3c47cbe"}, - {file = "debugpy-1.6.6-cp39-cp39-win_amd64.whl", hash = "sha256:de4a045fbf388e120bb6ec66501458d3134f4729faed26ff95de52a754abddb1"}, - {file = "debugpy-1.6.6-py2.py3-none-any.whl", hash = "sha256:be596b44448aac14eb3614248c91586e2bc1728e020e82ef3197189aae556115"}, - {file = "debugpy-1.6.6.zip", hash = "sha256:b9c2130e1c632540fbf9c2c88341493797ddf58016e7cba02e311de9b0a96b67"}, + {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"}, ] [[package]] name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -731,7 +712,6 @@ files = [ name = "defusedxml" version = "0.7.1" description = "XML bomb protection for Python stdlib modules" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -743,7 +723,6 @@ files = [ name = "distlib" version = "0.3.6" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ @@ -755,7 +734,6 @@ files = [ name = "docutils" version = "0.17.1" description = "Docutils -- Python Documentation Utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -765,75 +743,67 @@ files = [ [[package]] name = "dulwich" -version = "0.20.50" +version = "0.21.5" description = "Python Git Library" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "dulwich-0.20.50-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:97f02f8d500d4af08dc022d697c56e8539171acc3f575c2fe9acf3b078e5c8c9"}, - {file = "dulwich-0.20.50-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7301773e5cc16d521bc6490e73772a86a4d1d0263de506f08b54678cc4e2f061"}, - {file = "dulwich-0.20.50-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b70106580ed11f45f4c32d2831d0c9c9f359bc2415fff4a6be443e3a36811398"}, - {file = "dulwich-0.20.50-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f9c4f2455f966cad94648278fa9972e4695b35d04f82792fa58e1ea15dd83f0"}, - {file = "dulwich-0.20.50-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9163fbb021a8ad9c35a0814a5eedf45a8eb3a0b764b865d7016d901fc5a947fc"}, - {file = "dulwich-0.20.50-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:322ff8ff6aa4d6d36294cd36de1c84767eb1903c7db3e7b4475ad091febf5363"}, - {file = "dulwich-0.20.50-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5d3290a45651c8e534f8e83ae2e30322aefdd162f0f338bae2e79a6ee5a87513"}, - {file = "dulwich-0.20.50-cp310-cp310-win32.whl", hash = "sha256:80ab07131a6e68594441f5c4767e9e44e87fceafc3e347e541c928a18c679bd8"}, - {file = "dulwich-0.20.50-cp310-cp310-win_amd64.whl", hash = "sha256:eefe786a6010f8546baac4912113eeed4e397ddb8c433a345b548a04d4176496"}, - {file = "dulwich-0.20.50-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:df3562dde3079d57287c233d45b790bc967c5aae975c9a7b07ca30e60e055512"}, - {file = "dulwich-0.20.50-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e1ae18d5805f0c0c5dac65795f8d48660437166b12ee2c0ffea95bfdbf9c1051"}, - {file = "dulwich-0.20.50-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d2f7df39bd1378d3b0bfb3e7fc930fd0191924af1f0ef587bcd9946afe076c06"}, - {file = "dulwich-0.20.50-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:731e7f319b34251fadeb362ada1d52cc932369d9cdfa25c0e41150cda28773d0"}, - {file = "dulwich-0.20.50-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d11d44176e5d2fa8271fc86ad1e0a8731b9ad8f77df64c12846b30e16135eb"}, - {file = "dulwich-0.20.50-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7aaabb8e4beadd53f75f853a981caaadef3ef130e5645c902705704eaf136daa"}, - {file = "dulwich-0.20.50-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c3dc9f97ec8d3db08d9723b9fd06f3e52c15b84c800d153cfb59b0a3dc8b8d40"}, - {file = "dulwich-0.20.50-cp311-cp311-win32.whl", hash = "sha256:3b1964fa80cafd5a1fd71615b0313daf6f3295c6ab05656ea0c1d2423539904a"}, - {file = "dulwich-0.20.50-cp311-cp311-win_amd64.whl", hash = "sha256:a24a3893108f3b97beb958670d5f3f2a3bec73a1fe18637a572a85abd949a1c4"}, - {file = "dulwich-0.20.50-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6d409a282f8848fd6c8d7c7545ad2f75c16de5d5977de202642f1d50fdaac554"}, - {file = "dulwich-0.20.50-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5411d0f1092152e1c0bb916ae490fe181953ae1b8d13f4e68661253e10b78dbb"}, - {file = "dulwich-0.20.50-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6343569f998ce429e2a5d813c56768ac51b496522401db950f0aa44240bfa901"}, - {file = "dulwich-0.20.50-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a405cd236766060894411614a272cfb86fe86cde5ca73ef264fc4fa5a715fff4"}, - {file = "dulwich-0.20.50-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ee0f9b02019c0ea84cdd31c00a0c283669b771c85612997a911715cf84e33d99"}, - {file = "dulwich-0.20.50-cp36-cp36m-win32.whl", hash = "sha256:2644466270267270f2157ea6f1c0aa224f6f3bf06a307fc39954e6b4b3d82bae"}, - {file = "dulwich-0.20.50-cp36-cp36m-win_amd64.whl", hash = "sha256:d4629635a97e3af1b5da48071e00c8e70fad85f3266fadabe1f5a8f49172c507"}, - {file = "dulwich-0.20.50-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0e4862f318d99cc8a500e3622a89613a88c07d957a0f628cdc2ed86addff790f"}, - {file = "dulwich-0.20.50-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c96e3fb9d48c0454dc242c7accc7819780c9a7f29e441a9eff12361ed0fa35f9"}, - {file = "dulwich-0.20.50-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cc6092a4f0bbbff2e553e87a9c6325955b64ea43fca21297c8182e19ae8a43c"}, - {file = "dulwich-0.20.50-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:519b627d49d273e2fd01c79d09e578675ca6cd05193c1787e9ef165c9a1d66ea"}, - {file = "dulwich-0.20.50-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a75cab01b909c4c683c2083e060e378bc01701b7366b5a7d9846ef6d3b9e3d5"}, - {file = "dulwich-0.20.50-cp37-cp37m-win32.whl", hash = "sha256:ea8ffe26d91dbcd5580dbd5a07270a12ea57b091604d77184da0a0d9fad50ed3"}, - {file = "dulwich-0.20.50-cp37-cp37m-win_amd64.whl", hash = "sha256:8f3af857f94021cae1322d86925bfc0dd31e501e885ab5db275473bfac0bb39d"}, - {file = "dulwich-0.20.50-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3fb35cedb1243bc420d885ef5b4afd642c6ac8f07ddfc7fdbca1becf9948bf7e"}, - {file = "dulwich-0.20.50-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4bb23a9cec63e16c0e432335f068169b73dd44fa9318dd7cd7a4ca83607ff367"}, - {file = "dulwich-0.20.50-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5267619b34ddaf8d9a6b841492cd17a971fd25bf9a5657f2de928385c3a08b94"}, - {file = "dulwich-0.20.50-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9091f1d53a3c0747cbf0bd127c64e7f09b770264d8fb53e284383fcdf69154e7"}, - {file = "dulwich-0.20.50-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6ec7c8fea2b44187a3b545e6c11ab9947ffb122647b07abcdb7cc3aaa770c0e"}, - {file = "dulwich-0.20.50-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:11b180b80363b4fc70664197028181a17ae4c52df9965a29b62a6c52e40c2dbe"}, - {file = "dulwich-0.20.50-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c83e7840d9d0a94d7033bc109efe0c22dfcdcd816bcd4469085e42809e3bf5ba"}, - {file = "dulwich-0.20.50-cp38-cp38-win32.whl", hash = "sha256:c075f69c2de19d9fd97e3b70832d2b42c6a4a5d909b3ffd1963b67d86029f95f"}, - {file = "dulwich-0.20.50-cp38-cp38-win_amd64.whl", hash = "sha256:06775c5713cfeda778c7c67d4422b5e7554d3a7f644f1dde646cdf486a30285a"}, - {file = "dulwich-0.20.50-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:49f66f1c057c18d7d60363f461f4ab8329320fbe1f02a7a33c255864a7d3c942"}, - {file = "dulwich-0.20.50-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4e541cd690a5e3d55082ed51732d755917e933cddeb4b0204f2a5ec5d5d7b60b"}, - {file = "dulwich-0.20.50-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:80e8750ee2fa0ab2784a095956077758e5f6107de27f637c4b9d18406652c22c"}, - {file = "dulwich-0.20.50-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fbb6368f18451dc44c95c55e1a609d1a01d3821f7ed480b22b2aea1baca0f4a7"}, - {file = "dulwich-0.20.50-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3ee45001411b638641819b7b3b33f31f13467c84066e432256580fcab7d8815"}, - {file = "dulwich-0.20.50-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4842e22ed863a776b36ef8ffe9ed7b772eb452b42c8d02975c29d27e3bc50ab4"}, - {file = "dulwich-0.20.50-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:790e4a641284a7fb4d56ebdaf8b324a5826fbbb9c54307c06f586f9f6a5e56db"}, - {file = "dulwich-0.20.50-cp39-cp39-win32.whl", hash = "sha256:f08406b6b789dea5c95ba1130a0801d8748a67f18be940fe7486a8b481fde875"}, - {file = "dulwich-0.20.50-cp39-cp39-win_amd64.whl", hash = "sha256:78c388ad421199000fb7b5ed5f0c7b509b3e31bd7cad303786a4d0bf89b82f60"}, - {file = "dulwich-0.20.50-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:cb194c53109131bcbcd1ca430fcd437cdaf2d33e204e45fbe121c47eaa43e9af"}, - {file = "dulwich-0.20.50-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7542a72c5640dd0620862d6df8688f02a6c336359b5af9b3fcfe11b7fa6652f"}, - {file = "dulwich-0.20.50-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aa1d0861517ebbbe0e0084cc9ab4f7ab720624a3eda2bd10e45f774ab858db8"}, - {file = "dulwich-0.20.50-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:583c6bbc27f13fe2e41a19f6987a42681c6e4f6959beae0a6e5bb033b8b081a8"}, - {file = "dulwich-0.20.50-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0c61c193d02c0e1e0d758cdd57ae76685c368d09a01f00d704ba88bd96767cfe"}, - {file = "dulwich-0.20.50-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2edbff3053251985f10702adfafbee118298d383ef5b5b432a5f22d1f1915df"}, - {file = "dulwich-0.20.50-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a344230cadfc5d315752add6ce9d4cfcfc6c85e36bbf57fce9444bcc7c6ea8fb"}, - {file = "dulwich-0.20.50-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:57bff9bde0b6b05b00c6acbb1a94357caddb2908ed7026a48c715ff50d220335"}, - {file = "dulwich-0.20.50-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e29a3c2037761fa816aa556e78364dfc8e3f44b873db2d17aed96f9b06ac83a3"}, - {file = "dulwich-0.20.50-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2aa2a4a84029625bf9c63771f8a628db1f3be2d2ea3cb8b17942cd4317797152"}, - {file = "dulwich-0.20.50-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd9fa00971ecf059bb358085a942ecac5be4ff71acdf299f44c8cbc45c18659f"}, - {file = "dulwich-0.20.50-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4adac92fb95671ea3a24f2f8e5e5e8f638711ce9c33a3ca6cd68bf1ff7d99f"}, - {file = "dulwich-0.20.50.tar.gz", hash = "sha256:50a941796b2c675be39be728d540c16b5b7ce77eb9e1b3f855650ece6832d2be"}, + {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"}, ] [package.dependencies] @@ -849,7 +819,6 @@ pgp = ["gpg"] name = "entrypoints" version = "0.4" description = "Discover and load entry points from installed packages." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -859,26 +828,24 @@ files = [ [[package]] name = "eradicate" -version = "2.1.0" +version = "2.2.0" description = "Removes commented-out code." -category = "dev" optional = false python-versions = "*" files = [ - {file = "eradicate-2.1.0-py3-none-any.whl", hash = "sha256:8bfaca181db9227dc88bdbce4d051a9627604c2243e7d85324f6d6ce0fd08bb2"}, - {file = "eradicate-2.1.0.tar.gz", hash = "sha256:aac7384ab25b1bf21c4c012de9b4bf8398945a14c98c911545b2ea50ab558014"}, + {file = "eradicate-2.2.0-py3-none-any.whl", hash = "sha256:751813c315a48ce7e3d0483410991015342d380a956e86e0265c61bfb875bcbc"}, + {file = "eradicate-2.2.0.tar.gz", hash = "sha256:c329a05def6a4b558dab58bb1b694f5209706b7c99ba174d226dfdb69a5ba0da"}, ] [[package]] name = "exceptiongroup" -version = "1.1.0" +version = "1.1.1" description = "Backport of PEP 654 (exception groups)" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, - {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, + {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, + {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, ] [package.extras] @@ -888,7 +855,6 @@ test = ["pytest (>=6)"] name = "executing" version = "1.2.0" description = "Get the currently executing AST node of a frame, and other information" -category = "dev" optional = false python-versions = "*" files = [ @@ -901,14 +867,13 @@ tests = ["asttokens", "littleutils", "pytest", "rich"] [[package]] name = "fastjsonschema" -version = "2.16.2" +version = "2.17.1" description = "Fastest Python implementation of JSON schema" -category = "dev" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.16.2-py3-none-any.whl", hash = "sha256:21f918e8d9a1a4ba9c22e09574ba72267a6762d47822db9add95f6454e51cc1c"}, - {file = "fastjsonschema-2.16.2.tar.gz", hash = "sha256:01e366f25d9047816fe3d288cbfc3e10541daf0af2044763f3d0ade42476da18"}, + {file = "fastjsonschema-2.17.1-py3-none-any.whl", hash = "sha256:4b90b252628ca695280924d863fe37234eebadc29c5360d322571233dc9746e0"}, + {file = "fastjsonschema-2.17.1.tar.gz", hash = "sha256:f4eeb8a77cef54861dbf7424ac8ce71306f12cbb086c45131bcba2c6a4f726e3"}, ] [package.extras] @@ -916,25 +881,23 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.9.0" +version = "3.12.0" description = "A platform independent file lock." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"}, - {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"}, + {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, + {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "flake8" version = "4.0.1" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -951,7 +914,6 @@ pyflakes = ">=2.4.0,<2.5.0" name = "flake8-bandit" version = "3.0.0" description = "Automated security testing with bandit and flake8." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -969,7 +931,6 @@ pycodestyle = "*" name = "flake8-bugbear" version = "22.12.6" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -988,7 +949,6 @@ dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "tox"] name = "flake8-builtins" version = "1.5.3" description = "Check for python builtins being used as variables or parameters." -category = "dev" optional = false python-versions = "*" files = [ @@ -1004,14 +964,13 @@ test = ["coverage", "coveralls", "mock", "pytest", "pytest-cov"] [[package]] name = "flake8-comprehensions" -version = "3.10.1" +version = "3.12.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "flake8-comprehensions-3.10.1.tar.gz", hash = "sha256:412052ac4a947f36b891143430fef4859705af11b2572fbb689f90d372cf26ab"}, - {file = "flake8_comprehensions-3.10.1-py3-none-any.whl", hash = "sha256:d763de3c74bc18a79c039a7ec732e0a1985b0c79309ceb51e56401ad0a2cd44e"}, + {file = "flake8_comprehensions-3.12.0-py3-none-any.whl", hash = "sha256:013234637ec7dfcb7cd2900578fb53c512f81db909cefe371c019232695c362d"}, + {file = "flake8_comprehensions-3.12.0.tar.gz", hash = "sha256:419ef1a6e8de929203791a5e8ff5e3906caeba13eb3290eebdbf88a9078d502e"}, ] [package.dependencies] @@ -1021,7 +980,6 @@ flake8 = ">=3.0,<3.2.0 || >3.2.0" name = "flake8-docstrings" version = "1.7.0" description = "Extension for flake8 which uses pydocstyle to check docstrings" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1037,7 +995,6 @@ pydocstyle = ">=2.1" name = "flake8-eradicate" version = "1.4.0" description = "Flake8 plugin to find commented out code" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -1054,7 +1011,6 @@ flake8 = ">=3.5,<6" name = "flake8-isort" version = "4.2.0" description = "flake8 plugin that integrates isort ." -category = "dev" optional = false python-versions = "*" files = [ @@ -1073,7 +1029,6 @@ test = ["pytest-cov"] name = "flake8-mutable" version = "1.2.0" description = "mutable defaults flake8 extension" -category = "dev" optional = false python-versions = "*" files = [ @@ -1088,7 +1043,6 @@ flake8 = "*" name = "flake8-plugin-utils" version = "1.3.2" description = "The package provides base classes and utils for flake8 plugin writing" -category = "dev" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -1100,7 +1054,6 @@ files = [ name = "flake8-polyfill" version = "1.0.2" description = "Polyfill package for Flake8 plugins" -category = "dev" optional = false python-versions = "*" files = [ @@ -1115,7 +1068,6 @@ flake8 = "*" name = "flake8-pytest-style" version = "1.7.2" description = "A flake8 plugin checking common style issues or inconsistencies with pytest-based tests." -category = "dev" optional = false python-versions = ">=3.7.2,<4.0.0" files = [ @@ -1130,7 +1082,6 @@ flake8-plugin-utils = ">=1.3.2,<2.0.0" name = "flake8-spellcheck" version = "0.25.0" description = "Spellcheck variables, comments and docstrings" -category = "dev" optional = false python-versions = "*" files = [ @@ -1143,14 +1094,13 @@ flake8 = ">3.0.0" [[package]] name = "flakeheaven" -version = "3.2.1" +version = "3.3.0" description = "FlakeHeaven is a [Flake8](https://gitlab.com/pycqa/flake8) wrapper to make it cool." -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "flakeheaven-3.2.1-py3-none-any.whl", hash = "sha256:fdae542414a8cd327dbbc969bb18d5972379570f6562af21b4a83f67bdd6b87c"}, - {file = "flakeheaven-3.2.1.tar.gz", hash = "sha256:f2d54aedd98b817e94c8c0fcc0da1230b43dbf911ce38aa412d00eb5db6fb71d"}, + {file = "flakeheaven-3.3.0-py3-none-any.whl", hash = "sha256:ae246197a178845b30b63fc03023f7ba925cc84cc96314ec19807dafcd6b39a3"}, + {file = "flakeheaven-3.3.0.tar.gz", hash = "sha256:eb07860e028ff8dd56cce742c4766624a37a4ce397fd34300254ab623d13047b"}, ] [package.dependencies] @@ -1166,18 +1116,17 @@ docs = ["alabaster", "myst-parser (>=0.18.0,<0.19.0)", "pygments-github-lexers", [[package]] name = "fonttools" -version = "4.38.0" +version = "4.39.4" description = "Tools to manipulate font files" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "fonttools-4.38.0-py3-none-any.whl", hash = "sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"}, - {file = "fonttools-4.38.0.zip", hash = "sha256:2bb244009f9bf3fa100fc3ead6aeb99febe5985fa20afbfbaa2f8946c2fbdaf1"}, + {file = "fonttools-4.39.4-py3-none-any.whl", hash = "sha256:106caf6167c4597556b31a8d9175a3fdc0356fdcd70ab19973c3b0d4c893c461"}, + {file = "fonttools-4.39.4.zip", hash = "sha256:dba8d7cdb8e2bac1b3da28c5ed5960de09e59a2fe7e63bb73f5a59e57b0430d2"}, ] [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 (>=14.0.0)", "xattr", "zopfli (>=0.1.4)"] +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)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "scipy"] lxml = ["lxml (>=4.0,<5)"] @@ -1187,14 +1136,13 @@ repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=14.0.0)"] +unicode = ["unicodedata2 (>=15.0.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "gitdb" version = "4.0.10" description = "Git Object Database" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1209,7 +1157,6 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.31" description = "GitPython is a Python library used to interact with Git repositories" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1224,7 +1171,6 @@ gitdb = ">=4.0.1,<5" name = "html5lib" version = "1.1" description = "HTML parser based on the WHATWG HTML specification" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1246,7 +1192,6 @@ lxml = ["lxml"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1258,7 +1203,6 @@ files = [ name = "imagesize" version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1268,34 +1212,32 @@ files = [ [[package]] name = "importlib-metadata" -version = "4.13.0" +version = "6.6.0" description = "Read metadata from Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116"}, - {file = "importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d"}, + {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, + {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "importlib-resources" -version = "5.10.2" +version = "5.12.0" description = "Read resources from Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_resources-5.10.2-py3-none-any.whl", hash = "sha256:7d543798b0beca10b6a01ac7cafda9f822c54db9e8376a6bf57e0cbd74d486b6"}, - {file = "importlib_resources-5.10.2.tar.gz", hash = "sha256:e4a96c8cc0339647ff9a5e0550d9f276fc5a01ffa276012b58ec108cfd7b8484"}, + {file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"}, + {file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"}, ] [package.dependencies] @@ -1309,7 +1251,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1317,16 +1258,26 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "installer" +version = "0.7.0" +description = "A library for installing Python wheels." +optional = false +python-versions = ">=3.7" +files = [ + {file = "installer-0.7.0-py3-none-any.whl", hash = "sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53"}, + {file = "installer-0.7.0.tar.gz", hash = "sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631"}, +] + [[package]] name = "ipykernel" -version = "6.21.2" +version = "6.23.1" description = "IPython Kernel for Jupyter" -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.21.2-py3-none-any.whl", hash = "sha256:430d00549b6aaf49bd0f5393150691edb1815afa62d457ee6b1a66b25cb17874"}, - {file = "ipykernel-6.21.2.tar.gz", hash = "sha256:6e9213484e4ce1fb14267ee435e18f23cc3a0634e635b9fb4ed4677b84e0fdf8"}, + {file = "ipykernel-6.23.1-py3-none-any.whl", hash = "sha256:77aeffab056c21d16f1edccdc9e5ccbf7d96eb401bd6703610a21be8b068aadc"}, + {file = "ipykernel-6.23.1.tar.gz", hash = "sha256:1aba0ae8453e15e9bc6b24e497ef6840114afcdb832ae597f32137fa19d42a6f"}, ] [package.dependencies] @@ -1335,7 +1286,7 @@ comm = ">=0.1.1" debugpy = ">=1.6.5" ipython = ">=7.23.1" jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" matplotlib-inline = ">=0.1" nest-asyncio = "*" packaging = "*" @@ -1353,14 +1304,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio" [[package]] name = "ipython" -version = "8.10.0" +version = "8.12.2" description = "IPython: Productive Interactive Computing" -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "ipython-8.10.0-py3-none-any.whl", hash = "sha256:b38c31e8fc7eff642fc7c597061fff462537cf2314e3225a19c906b7b0d8a345"}, - {file = "ipython-8.10.0.tar.gz", hash = "sha256:b13a1d6c1f5818bd388db53b7107d17454129a70de2b87481d555daede5eb49e"}, + {file = "ipython-8.12.2-py3-none-any.whl", hash = "sha256:ea8801f15dfe4ffb76dea1b09b847430ffd70d827b41735c64a0638a04103bfc"}, + {file = "ipython-8.12.2.tar.gz", hash = "sha256:c7b80eb7f5a855a88efc971fda506ff7a91c280b42cdae26643e0f601ea281ea"}, ] [package.dependencies] @@ -1372,10 +1322,11 @@ jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} pickleshare = "*" -prompt-toolkit = ">=3.0.30,<3.1.0" +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5" +typing-extensions = {version = "*", markers = "python_version < \"3.10\""} [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"] @@ -1394,7 +1345,6 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa name = "isort" version = "5.12.0" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -1412,7 +1362,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "jaraco-classes" version = "3.2.3" description = "Utility functions for Python class constructs" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1431,7 +1380,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "jedi" version = "0.18.2" description = "An autocompletion tool for Python that can be used for text editors." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1451,7 +1399,6 @@ testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "jeepney" version = "0.8.0" description = "Low-level, pure Python DBus protocol wrapper." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1467,7 +1414,6 @@ trio = ["async_generator", "trio"] name = "jinja2" version = "3.0.3" description = "A very fast and expressive template engine." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1485,7 +1431,6 @@ i18n = ["Babel (>=2.7)"] name = "jsonschema" version = "4.17.3" description = "An implementation of JSON Schema validation for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1505,19 +1450,18 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jupyter-client" -version = "8.0.3" +version = "8.2.0" description = "Jupyter protocol implementation and client libraries" -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.0.3-py3-none-any.whl", hash = "sha256:be48ac6bd659cbbddb7a674cf06b3b8afbf53f228253cf58bde604c03bd487b0"}, - {file = "jupyter_client-8.0.3.tar.gz", hash = "sha256:ed65498bea6d876ef9d8da3e0db3dd33c5d129f5b2645f56ae03993782966bd0"}, + {file = "jupyter_client-8.2.0-py3-none-any.whl", hash = "sha256:b18219aa695d39e2ad570533e0d71fb7881d35a873051054a84ee2a17c4b7389"}, + {file = "jupyter_client-8.2.0.tar.gz", hash = "sha256:9fe233834edd0e6c0aa5f05ca2ab4bdea1842bfd2d8a932878212fc5301ddaf0"}, ] [package.dependencies] importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" python-dateutil = ">=2.8.2" pyzmq = ">=23.0" tornado = ">=6.2" @@ -1525,23 +1469,22 @@ traitlets = ">=5.3" [package.extras] docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["codecov", "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", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] [[package]] name = "jupyter-core" -version = "5.2.0" +version = "5.3.0" description = "Jupyter core package. A base package on which Jupyter projects rely." -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.2.0-py3-none-any.whl", hash = "sha256:4bdc2928c37f6917130c667d8b8708f20aee539d8283c6be72aabd2a4b4c83b0"}, - {file = "jupyter_core-5.2.0.tar.gz", hash = "sha256:1407cdb4c79ee467696c04b76633fc1884015fa109323365a6372c8e890cc83f"}, + {file = "jupyter_core-5.3.0-py3-none-any.whl", hash = "sha256:d4201af84559bc8c70cead287e1ab94aeef3c512848dde077b7684b54d67730d"}, + {file = "jupyter_core-5.3.0.tar.gz", hash = "sha256:6db75be0c83edbf1b7c9f91ec266a9a24ef945da630f3120e1a0046dc13713fc"}, ] [package.dependencies] platformdirs = ">=2.5" -pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} traitlets = ">=5.3" [package.extras] @@ -1552,7 +1495,6 @@ test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] name = "jupyterlab-pygments" version = "0.2.2" description = "Pygments theme using JupyterLab CSS variables" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1564,7 +1506,6 @@ files = [ name = "keyring" version = "23.13.1" description = "Store and access your passwords safely." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1589,7 +1530,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "kiwisolver" version = "1.4.4" description = "A fast implementation of the Cassowary constraint solver" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1667,7 +1607,6 @@ files = [ name = "linecache2" version = "1.0.0" description = "Backports of the linecache module" -category = "dev" optional = false python-versions = "*" files = [ @@ -1679,7 +1618,6 @@ files = [ name = "lockfile" version = "0.12.2" description = "Platform-independent file locking module" -category = "dev" optional = false python-versions = "*" files = [ @@ -1689,113 +1627,111 @@ files = [ [[package]] name = "markupsafe" -version = "2.1.2" +version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, - {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, + {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-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"}, ] [[package]] name = "matplotlib" -version = "3.7.0" +version = "3.7.1" description = "Python plotting package" -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "matplotlib-3.7.0-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:3da8b9618188346239e51f1ea6c0f8f05c6e218cfcc30b399dd7dd7f52e8bceb"}, - {file = "matplotlib-3.7.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c0592ba57217c22987b7322df10f75ef95bc44dce781692b4b7524085de66019"}, - {file = "matplotlib-3.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:21269450243d6928da81a9bed201f0909432a74e7d0d65db5545b9fa8a0d0223"}, - {file = "matplotlib-3.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb2e76cd429058d8954121c334dddfcd11a6186c6975bca61f3f248c99031b05"}, - {file = "matplotlib-3.7.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de20eb1247725a2f889173d391a6d9e7e0f2540feda24030748283108b0478ec"}, - {file = "matplotlib-3.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5465735eaaafd1cfaec3fed60aee776aeb3fd3992aa2e49f4635339c931d443"}, - {file = "matplotlib-3.7.0-cp310-cp310-win32.whl", hash = "sha256:092e6abc80cdf8a95f7d1813e16c0e99ceda8d5b195a3ab859c680f3487b80a2"}, - {file = "matplotlib-3.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:4f640534ec2760e270801056bc0d8a10777c48b30966eef78a7c35d8590915ba"}, - {file = "matplotlib-3.7.0-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:f336e7014889c38c59029ebacc35c59236a852e4b23836708cfd3f43d1eaeed5"}, - {file = "matplotlib-3.7.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3a10428d4f8d1a478ceabd652e61a175b2fdeed4175ab48da4a7b8deb561e3fa"}, - {file = "matplotlib-3.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46ca923e980f76d34c1c633343a72bb042d6ba690ecc649aababf5317997171d"}, - {file = "matplotlib-3.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c849aa94ff2a70fb71f318f48a61076d1205c6013b9d3885ade7f992093ac434"}, - {file = "matplotlib-3.7.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:827e78239292e561cfb70abf356a9d7eaf5bf6a85c97877f254009f20b892f89"}, - {file = "matplotlib-3.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:691ef1f15360e439886186d0db77b5345b24da12cbc4fc57b26c4826db4d6cab"}, - {file = "matplotlib-3.7.0-cp311-cp311-win32.whl", hash = "sha256:21a8aeac39b4a795e697265d800ce52ab59bdeb6bb23082e2d971f3041074f02"}, - {file = "matplotlib-3.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:01681566e95b9423021b49dea6a2395c16fa054604eacb87f0f4c439750f9114"}, - {file = "matplotlib-3.7.0-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:cf119eee4e57389fba5ac8b816934e95c256535e55f0b21628b4205737d1de85"}, - {file = "matplotlib-3.7.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:21bd4033c40b95abd5b8453f036ed5aa70856e56ecbd887705c37dce007a4c21"}, - {file = "matplotlib-3.7.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:111ef351f28fd823ed7177632070a6badd6f475607122bc9002a526f2502a0b5"}, - {file = "matplotlib-3.7.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f91d35b3ef51d29d9c661069b9e4ba431ce283ffc533b981506889e144b5b40e"}, - {file = "matplotlib-3.7.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0a776462a4a63c0bfc9df106c15a0897aa2dbab6795c693aa366e8e283958854"}, - {file = "matplotlib-3.7.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dfd4a0cbd151f6439e6d7f8dca5292839ca311e7e650596d073774847ca2e4f"}, - {file = "matplotlib-3.7.0-cp38-cp38-win32.whl", hash = "sha256:56b7b79488209041a9bf7ddc34f1b069274489ce69e34dc63ae241d0d6b4b736"}, - {file = "matplotlib-3.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:8665855f3919c80551f377bc16df618ceabf3ef65270bc14b60302dce88ca9ab"}, - {file = "matplotlib-3.7.0-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:f910d924da8b9fb066b5beae0b85e34ed1b6293014892baadcf2a51da1c65807"}, - {file = "matplotlib-3.7.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:cf6346644e8fe234dc847e6232145dac199a650d3d8025b3ef65107221584ba4"}, - {file = "matplotlib-3.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d1e52365d8d5af699f04581ca191112e1d1220a9ce4386b57d807124d8b55e6"}, - {file = "matplotlib-3.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c869b646489c6a94375714032e5cec08e3aa8d3f7d4e8ef2b0fb50a52b317ce6"}, - {file = "matplotlib-3.7.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4ddac5f59e78d04b20469bc43853a8e619bb6505c7eac8ffb343ff2c516d72f"}, - {file = "matplotlib-3.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb0304c1cd802e9a25743414c887e8a7cd51d96c9ec96d388625d2cd1c137ae3"}, - {file = "matplotlib-3.7.0-cp39-cp39-win32.whl", hash = "sha256:a06a6c9822e80f323549c6bc9da96d4f233178212ad9a5f4ab87fd153077a507"}, - {file = "matplotlib-3.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:cb52aa97b92acdee090edfb65d1cb84ea60ab38e871ba8321a10bbcebc2a3540"}, - {file = "matplotlib-3.7.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3493b48e56468c39bd9c1532566dff3b8062952721b7521e1f394eb6791495f4"}, - {file = "matplotlib-3.7.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d0dcd1a0bf8d56551e8617d6dc3881d8a1c7fb37d14e5ec12cbb293f3e6170a"}, - {file = "matplotlib-3.7.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51fb664c37714cbaac69c16d6b3719f517a13c96c3f76f4caadd5a0aa7ed0329"}, - {file = "matplotlib-3.7.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4497d88c559b76da320b7759d64db442178beeea06a52dc0c629086982082dcd"}, - {file = "matplotlib-3.7.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9d85355c48ef8b9994293eb7c00f44aa8a43cad7a297fbf0770a25cdb2244b91"}, - {file = "matplotlib-3.7.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:03eb2c8ff8d85da679b71e14c7c95d16d014c48e0c0bfa14db85f6cdc5c92aad"}, - {file = "matplotlib-3.7.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71b751d06b2ed1fd017de512d7439c0259822864ea16731522b251a27c0b2ede"}, - {file = "matplotlib-3.7.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b51ab8a5d5d3bbd4527af633a638325f492e09e45e78afdf816ef55217a09664"}, - {file = "matplotlib-3.7.0.tar.gz", hash = "sha256:8f6efd313430d7ef70a38a3276281cb2e8646b3a22b3b21eb227da20e15e6813"}, + {file = "matplotlib-3.7.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:95cbc13c1fc6844ab8812a525bbc237fa1470863ff3dace7352e910519e194b1"}, + {file = "matplotlib-3.7.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:08308bae9e91aca1ec6fd6dda66237eef9f6294ddb17f0d0b3c863169bf82353"}, + {file = "matplotlib-3.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:544764ba51900da4639c0f983b323d288f94f65f4024dc40ecb1542d74dc0500"}, + {file = "matplotlib-3.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d94989191de3fcc4e002f93f7f1be5da476385dde410ddafbb70686acf00ea"}, + {file = "matplotlib-3.7.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99bc9e65901bb9a7ce5e7bb24af03675cbd7c70b30ac670aa263240635999a4"}, + {file = "matplotlib-3.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb7d248c34a341cd4c31a06fd34d64306624c8cd8d0def7abb08792a5abfd556"}, + {file = "matplotlib-3.7.1-cp310-cp310-win32.whl", hash = "sha256:ce463ce590f3825b52e9fe5c19a3c6a69fd7675a39d589e8b5fbe772272b3a24"}, + {file = "matplotlib-3.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:3d7bc90727351fb841e4d8ae620d2d86d8ed92b50473cd2b42ce9186104ecbba"}, + {file = "matplotlib-3.7.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:770a205966d641627fd5cf9d3cb4b6280a716522cd36b8b284a8eb1581310f61"}, + {file = "matplotlib-3.7.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f67bfdb83a8232cb7a92b869f9355d677bce24485c460b19d01970b64b2ed476"}, + {file = "matplotlib-3.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2bf092f9210e105f414a043b92af583c98f50050559616930d884387d0772aba"}, + {file = "matplotlib-3.7.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89768d84187f31717349c6bfadc0e0d8c321e8eb34522acec8a67b1236a66332"}, + {file = "matplotlib-3.7.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83111e6388dec67822e2534e13b243cc644c7494a4bb60584edbff91585a83c6"}, + {file = "matplotlib-3.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a867bf73a7eb808ef2afbca03bcdb785dae09595fbe550e1bab0cd023eba3de0"}, + {file = "matplotlib-3.7.1-cp311-cp311-win32.whl", hash = "sha256:fbdeeb58c0cf0595efe89c05c224e0a502d1aa6a8696e68a73c3efc6bc354304"}, + {file = "matplotlib-3.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:c0bd19c72ae53e6ab979f0ac6a3fafceb02d2ecafa023c5cca47acd934d10be7"}, + {file = "matplotlib-3.7.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:6eb88d87cb2c49af00d3bbc33a003f89fd9f78d318848da029383bfc08ecfbfb"}, + {file = "matplotlib-3.7.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:cf0e4f727534b7b1457898c4f4ae838af1ef87c359b76dcd5330fa31893a3ac7"}, + {file = "matplotlib-3.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:46a561d23b91f30bccfd25429c3c706afe7d73a5cc64ef2dfaf2b2ac47c1a5dc"}, + {file = "matplotlib-3.7.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8704726d33e9aa8a6d5215044b8d00804561971163563e6e6591f9dcf64340cc"}, + {file = "matplotlib-3.7.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4cf327e98ecf08fcbb82685acaf1939d3338548620ab8dfa02828706402c34de"}, + {file = "matplotlib-3.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:617f14ae9d53292ece33f45cba8503494ee199a75b44de7717964f70637a36aa"}, + {file = "matplotlib-3.7.1-cp38-cp38-win32.whl", hash = "sha256:7c9a4b2da6fac77bcc41b1ea95fadb314e92508bf5493ceff058e727e7ecf5b0"}, + {file = "matplotlib-3.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:14645aad967684e92fc349493fa10c08a6da514b3d03a5931a1bac26e6792bd1"}, + {file = "matplotlib-3.7.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:81a6b377ea444336538638d31fdb39af6be1a043ca5e343fe18d0f17e098770b"}, + {file = "matplotlib-3.7.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:28506a03bd7f3fe59cd3cd4ceb2a8d8a2b1db41afede01f66c42561b9be7b4b7"}, + {file = "matplotlib-3.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c587963b85ce41e0a8af53b9b2de8dddbf5ece4c34553f7bd9d066148dc719c"}, + {file = "matplotlib-3.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8bf26ade3ff0f27668989d98c8435ce9327d24cffb7f07d24ef609e33d582439"}, + {file = "matplotlib-3.7.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:def58098f96a05f90af7e92fd127d21a287068202aa43b2a93476170ebd99e87"}, + {file = "matplotlib-3.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f883a22a56a84dba3b588696a2b8a1ab0d2c3d41be53264115c71b0a942d8fdb"}, + {file = "matplotlib-3.7.1-cp39-cp39-win32.whl", hash = "sha256:4f99e1b234c30c1e9714610eb0c6d2f11809c9c78c984a613ae539ea2ad2eb4b"}, + {file = "matplotlib-3.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:3ba2af245e36990facf67fde840a760128ddd71210b2ab6406e640188d69d136"}, + {file = "matplotlib-3.7.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3032884084f541163f295db8a6536e0abb0db464008fadca6c98aaf84ccf4717"}, + {file = "matplotlib-3.7.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a2cb34336110e0ed8bb4f650e817eed61fa064acbefeb3591f1b33e3a84fd96"}, + {file = "matplotlib-3.7.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b867e2f952ed592237a1828f027d332d8ee219ad722345b79a001f49df0936eb"}, + {file = "matplotlib-3.7.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:57bfb8c8ea253be947ccb2bc2d1bb3862c2bccc662ad1b4626e1f5e004557042"}, + {file = "matplotlib-3.7.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:438196cdf5dc8d39b50a45cb6e3f6274edbcf2254f85fa9b895bf85851c3a613"}, + {file = "matplotlib-3.7.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:21e9cff1a58d42e74d01153360de92b326708fb205250150018a52c70f43c290"}, + {file = "matplotlib-3.7.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d4725d70b7c03e082bbb8a34639ede17f333d7247f56caceb3801cb6ff703d"}, + {file = "matplotlib-3.7.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:97cc368a7268141afb5690760921765ed34867ffb9655dd325ed207af85c7529"}, + {file = "matplotlib-3.7.1.tar.gz", hash = "sha256:7b73305f25eab4541bd7ee0b96d87e53ae9c9f1823be5659b806cd85786fe882"}, ] [package.dependencies] @@ -1814,7 +1750,6 @@ python-dateutil = ">=2.7" name = "matplotlib-inline" version = "0.1.6" description = "Inline Matplotlib backend for Jupyter" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1829,7 +1764,6 @@ traitlets = "*" name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = "*" files = [ @@ -1841,7 +1775,6 @@ files = [ name = "mistune" version = "2.0.5" description = "A sane Markdown parser with useful plugins and renderers" -category = "dev" optional = false python-versions = "*" files = [ @@ -1851,111 +1784,118 @@ files = [ [[package]] name = "more-itertools" -version = "9.0.0" +version = "9.1.0" description = "More routines for operating on iterables, beyond itertools" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "more-itertools-9.0.0.tar.gz", hash = "sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab"}, - {file = "more_itertools-9.0.0-py3-none-any.whl", hash = "sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41"}, + {file = "more-itertools-9.1.0.tar.gz", hash = "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d"}, + {file = "more_itertools-9.1.0-py3-none-any.whl", hash = "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"}, ] [[package]] name = "msgpack" -version = "1.0.4" +version = "1.0.5" description = "MessagePack serializer" -category = "dev" optional = false python-versions = "*" files = [ - {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250"}, - {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88"}, - {file = "msgpack-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467"}, - {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6"}, - {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa"}, - {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6"}, - {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba"}, - {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e"}, - {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db"}, - {file = "msgpack-1.0.4-cp310-cp310-win32.whl", hash = "sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef"}, - {file = "msgpack-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075"}, - {file = "msgpack-1.0.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52"}, - {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9"}, - {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9"}, - {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08"}, - {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8"}, - {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6"}, - {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae"}, - {file = "msgpack-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6"}, - {file = "msgpack-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661"}, - {file = "msgpack-1.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c"}, - {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0"}, - {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227"}, - {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff"}, - {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd"}, - {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e"}, - {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236"}, - {file = "msgpack-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44"}, - {file = "msgpack-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1"}, - {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d"}, - {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab"}, - {file = "msgpack-1.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb"}, - {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9"}, - {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e"}, - {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1"}, - {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e"}, - {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43"}, - {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243"}, - {file = "msgpack-1.0.4-cp38-cp38-win32.whl", hash = "sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2"}, - {file = "msgpack-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6"}, - {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae"}, - {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55"}, - {file = "msgpack-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da"}, - {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f"}, - {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92"}, - {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f"}, - {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624"}, - {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8"}, - {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae"}, - {file = "msgpack-1.0.4-cp39-cp39-win32.whl", hash = "sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c"}, - {file = "msgpack-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce"}, - {file = "msgpack-1.0.4.tar.gz", hash = "sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f"}, + {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"}, ] [[package]] name = "nbclient" -version = "0.7.2" +version = "0.8.0" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." -category = "dev" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "nbclient-0.7.2-py3-none-any.whl", hash = "sha256:d97ac6257de2794f5397609df754fcbca1a603e94e924eb9b99787c031ae2e7c"}, - {file = "nbclient-0.7.2.tar.gz", hash = "sha256:884a3f4a8c4fc24bb9302f263e0af47d97f0d01fe11ba714171b320c8ac09547"}, + {file = "nbclient-0.8.0-py3-none-any.whl", hash = "sha256:25e861299e5303a0477568557c4045eccc7a34c17fc08e7959558707b9ebe548"}, + {file = "nbclient-0.8.0.tar.gz", hash = "sha256:f9b179cd4b2d7bca965f900a2ebf0db4a12ebff2f36a711cb66861e4ae158e55"}, ] [package.dependencies] jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" nbformat = ">=5.1" -traitlets = ">=5.3" +traitlets = ">=5.4" [package.extras] dev = ["pre-commit"] -docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme"] -test = ["ipykernel", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] +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"] [[package]] name = "nbconvert" -version = "7.2.9" +version = "7.2.10" description = "Converting Jupyter Notebooks" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "nbconvert-7.2.9-py3-none-any.whl", hash = "sha256:495638c5e06005f4a5ce828d8a81d28e34f95c20f4384d5d7a22254b443836e7"}, - {file = "nbconvert-7.2.9.tar.gz", hash = "sha256:a42c3ac137c64f70cbe4d763111bf358641ea53b37a01a5c202ed86374af5234"}, + {file = "nbconvert-7.2.10-py3-none-any.whl", hash = "sha256:e41118f81698d3d59b3c7c2887937446048f741aba6c367c1c1a77810b3e2d08"}, + {file = "nbconvert-7.2.10.tar.gz", hash = "sha256:8eed67bd8314f3ec87c4351c2f674af3a04e5890ab905d6bd927c05aec1cf27d"}, ] [package.dependencies] @@ -1987,14 +1927,13 @@ webpdf = ["pyppeteer (>=1,<1.1)"] [[package]] name = "nbformat" -version = "5.7.3" +version = "5.9.0" description = "The Jupyter Notebook format" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "nbformat-5.7.3-py3-none-any.whl", hash = "sha256:22a98a6516ca216002b0a34591af5bcb8072ca6c63910baffc901cfa07fefbf0"}, - {file = "nbformat-5.7.3.tar.gz", hash = "sha256:4b021fca24d3a747bf4e626694033d792d594705829e5e35b14ee3369f9f6477"}, + {file = "nbformat-5.9.0-py3-none-any.whl", hash = "sha256:8c8fa16d6d05062c26177754bfbfac22de644888e2ef69d27ad2a334cf2576e5"}, + {file = "nbformat-5.9.0.tar.gz", hash = "sha256:e98ebb6120c3efbafdee2a40af2a140cadee90bb06dd69a2a63d9551fcc7f976"}, ] [package.dependencies] @@ -2011,7 +1950,6 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] name = "nest-asyncio" version = "1.5.6" description = "Patch asyncio to allow nested event loops" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2023,7 +1961,6 @@ files = [ name = "networkx" version = "2.8.7" description = "Python package for creating and manipulating graphs and networks" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2040,59 +1977,56 @@ test = ["codecov (>=2.1)", "pytest (>=7.1)", "pytest-cov (>=3.0)"] [[package]] name = "numpy" -version = "1.24.2" +version = "1.24.3" description = "Fundamental package for array computing in Python" -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, - {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, - {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, - {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, - {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, - {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, - {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, - {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, - {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, - {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, - {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, + {file = "numpy-1.24.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1104d3c036fb81ab923f507536daedc718d0ad5a8707c6061cdfd6d184e570"}, + {file = "numpy-1.24.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:202de8f38fc4a45a3eea4b63e2f376e5f2dc64ef0fa692838e31a808520efaf7"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8535303847b89aa6b0f00aa1dc62867b5a32923e4d1681a35b5eef2d9591a463"}, + {file = "numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d926b52ba1367f9acb76b0df6ed21f0b16a1ad87c6720a1121674e5cf63e2b6"}, + {file = "numpy-1.24.3-cp310-cp310-win32.whl", hash = "sha256:f21c442fdd2805e91799fbe044a7b999b8571bb0ab0f7850d0cb9641a687092b"}, + {file = "numpy-1.24.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f23af8c16022663a652d3b25dcdc272ac3f83c3af4c02eb8b824e6b3ab9d7"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a7721ec204d3a237225db3e194c25268faf92e19338a35f3a224469cb6039a3"}, + {file = "numpy-1.24.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d6cc757de514c00b24ae8cf5c876af2a7c3df189028d68c0cb4eaa9cd5afc2bf"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e3f4e85fc5d4fd311f6e9b794d0c00e7002ec122be271f2019d63376f1d385"}, + {file = "numpy-1.24.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1d3c026f57ceaad42f8231305d4653d5f05dc6332a730ae5c0bea3513de0950"}, + {file = "numpy-1.24.3-cp311-cp311-win32.whl", hash = "sha256:c91c4afd8abc3908e00a44b2672718905b8611503f7ff87390cc0ac3423fb096"}, + {file = "numpy-1.24.3-cp311-cp311-win_amd64.whl", hash = "sha256:5342cf6aad47943286afa6f1609cad9b4266a05e7f2ec408e2cf7aea7ff69d80"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7776ea65423ca6a15255ba1872d82d207bd1e09f6d0894ee4a64678dd2204078"}, + {file = "numpy-1.24.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ae8d0be48d1b6ed82588934aaaa179875e7dc4f3d84da18d7eae6eb3f06c242c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecde0f8adef7dfdec993fd54b0f78183051b6580f606111a6d789cd14c61ea0c"}, + {file = "numpy-1.24.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4749e053a29364d3452c034827102ee100986903263e89884922ef01a0a6fd2f"}, + {file = "numpy-1.24.3-cp38-cp38-win32.whl", hash = "sha256:d933fabd8f6a319e8530d0de4fcc2e6a61917e0b0c271fded460032db42a0fe4"}, + {file = "numpy-1.24.3-cp38-cp38-win_amd64.whl", hash = "sha256:56e48aec79ae238f6e4395886b5eaed058abb7231fb3361ddd7bfdf4eed54289"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4719d5aefb5189f50887773699eaf94e7d1e02bf36c1a9d353d9f46703758ca4"}, + {file = "numpy-1.24.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ec87a7084caa559c36e0a2309e4ecb1baa03b687201d0a847c8b0ed476a7187"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8282b9bcfe2b5e7d491d0bf7f3e2da29700cec05b49e64d6246923329f2b02"}, + {file = "numpy-1.24.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210461d87fb02a84ef243cac5e814aad2b7f4be953b32cb53327bb49fd77fbb4"}, + {file = "numpy-1.24.3-cp39-cp39-win32.whl", hash = "sha256:784c6da1a07818491b0ffd63c6bbe5a33deaa0e25a20e1b3ea20cf0e43f8046c"}, + {file = "numpy-1.24.3-cp39-cp39-win_amd64.whl", hash = "sha256:d5036197ecae68d7f491fcdb4df90082b0d4960ca6599ba2659957aafced7c17"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:352ee00c7f8387b44d19f4cada524586f07379c0d49270f87233983bc5087ca0"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7d6acc2e7524c9955e5c903160aa4ea083736fde7e91276b0e5d98e6332812"}, + {file = "numpy-1.24.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:35400e6a8d102fd07c71ed7dcadd9eb62ee9a6e84ec159bd48c28235bbb0f8e4"}, + {file = "numpy-1.24.3.tar.gz", hash = "sha256:ab344f1bf21f140adab8e47fdbc7c35a477dc01408791f8ba00d018dd0bc5155"}, ] [[package]] name = "packaging" -version = "23.0" +version = "23.1" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] [[package]] name = "pandas" version = "1.5.3" description = "Powerful data structures for data analysis, time series, and statistics" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2140,7 +2074,6 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] name = "pandocfilters" version = "1.5.0" description = "Utilities for writing pandoc filters in python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2152,7 +2085,6 @@ files = [ name = "parso" version = "0.8.3" description = "A Python Parser" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2168,7 +2100,6 @@ testing = ["docopt", "pytest (<6.0.0)"] name = "pbr" version = "5.11.1" description = "Python Build Reasonableness" -category = "dev" optional = false python-versions = ">=2.6" files = [ @@ -2180,7 +2111,6 @@ files = [ name = "pep8-naming" version = "0.12.1" description = "Check PEP-8 naming conventions, plugin for flake8" -category = "dev" optional = false python-versions = "*" files = [ @@ -2196,7 +2126,6 @@ flake8-polyfill = ">=1.0.2,<2" name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." -category = "dev" optional = false python-versions = "*" files = [ @@ -2211,7 +2140,6 @@ ptyprocess = ">=0.5" name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" -category = "dev" optional = false python-versions = "*" files = [ @@ -2221,100 +2149,87 @@ files = [ [[package]] name = "pillow" -version = "9.4.0" +version = "9.5.0" description = "Python Imaging Library (Fork)" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "Pillow-9.4.0-1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b4b4e9dda4f4e4c4e6896f93e84a8f0bcca3b059de9ddf67dac3c334b1195e1"}, - {file = "Pillow-9.4.0-1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fb5c1ad6bad98c57482236a21bf985ab0ef42bd51f7ad4e4538e89a997624e12"}, - {file = "Pillow-9.4.0-1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:f0caf4a5dcf610d96c3bd32932bfac8aee61c96e60481c2a0ea58da435e25acd"}, - {file = "Pillow-9.4.0-1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:3f4cc516e0b264c8d4ccd6b6cbc69a07c6d582d8337df79be1e15a5056b258c9"}, - {file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"}, - {file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"}, - {file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"}, - {file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"}, - {file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"}, - {file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"}, - {file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"}, - {file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"}, - {file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"}, - {file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, - {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, - {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, - {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, - {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, - {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, - {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, - {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, - {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, - {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, - {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, - {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, - {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] + {file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"}, + {file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"}, + {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"}, + {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"}, + {file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"}, + {file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"}, + {file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"}, + {file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"}, + {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"}, + {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"}, + {file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"}, + {file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"}, + {file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"}, + {file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"}, + {file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"}, + {file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"}, + {file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"}, + {file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"}, + {file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"}, + {file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"}, + {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"}, + {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"}, + {file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"}, + {file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"}, + {file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"}, + {file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"}, + {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"}, + {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"}, + {file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"}, + {file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"}, + {file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] [[package]] name = "pkginfo" version = "1.9.6" description = "Query metadata from sdists / bdists / installed packages." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2329,7 +2244,6 @@ testing = ["pytest", "pytest-cov"] name = "pkgutil-resolve-name" version = "1.3.10" description = "Resolve a name to an object." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2339,25 +2253,23 @@ files = [ [[package]] name = "platformdirs" -version = "2.6.2" +version = "3.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, - {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, + {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, + {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2371,84 +2283,80 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "poetry" -version = "1.3.2" +version = "1.5.1" description = "Python dependency management and packaging made easy." -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "poetry-1.3.2-py3-none-any.whl", hash = "sha256:41980d557954b1418fa503de7a8fb25f19c03c0223a171666b305f05a45fc206"}, - {file = "poetry-1.3.2.tar.gz", hash = "sha256:26ded25f0cf67943243ca4f0aafd47ec4668bdb62845dbb8c2b0e3d9cd280bf4"}, + {file = "poetry-1.5.1-py3-none-any.whl", hash = "sha256:dfc7ce3a38ae216c0465694e2e674bef6eb1a2ba81aa47a26f9dc03362fe2f5f"}, + {file = "poetry-1.5.1.tar.gz", hash = "sha256:cc7ea4524d1a11558006224bfe8ba8ed071417d4eb5ef6c89decc6a37d437eeb"}, ] [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" crashtest = ">=0.4.1,<0.5.0" -dulwich = ">=0.20.46,<0.21.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,<5.0", markers = "python_version < \"3.10\""} +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} +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" pexpect = ">=4.7.0,<5.0.0" -pkginfo = ">=1.5,<2.0" -platformdirs = ">=2.5.2,<3.0.0" -poetry-core = "1.4.0" -poetry-plugin-export = ">=1.2.0,<2.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" +pyproject-hooks = ">=1.0.0,<2.0.0" requests = ">=2.18,<3.0" -requests-toolbelt = ">=0.9.1,<0.11.0" +requests-toolbelt = ">=0.9.1,<2" shellingham = ">=1.5,<2.0" tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} -tomlkit = ">=0.11.1,<0.11.2 || >0.11.2,<0.11.3 || >0.11.3,<1.0.0" +tomlkit = ">=0.11.4,<1.0.0" trove-classifiers = ">=2022.5.19" urllib3 = ">=1.26.0,<2.0.0" -virtualenv = [ - {version = ">=20.4.3,<20.4.5 || >20.4.5,<20.4.6 || >20.4.6,<21.0.0", markers = "sys_platform != \"win32\" or python_version != \"3.9\""}, - {version = ">=20.4.3,<20.4.5 || >20.4.5,<20.4.6 || >20.4.6,<20.16.6", markers = "sys_platform == \"win32\" and python_version == \"3.9\""}, -] +virtualenv = ">=20.22.0,<21.0.0" xattr = {version = ">=0.10.0,<0.11.0", markers = "sys_platform == \"darwin\""} [[package]] name = "poetry-core" -version = "1.4.0" +version = "1.6.1" description = "Poetry PEP 517 Build Backend" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "poetry_core-1.4.0-py3-none-any.whl", hash = "sha256:5559ab80384ac021db329ef317086417e140ee1176bcfcb3a3838b544e213c8e"}, - {file = "poetry_core-1.4.0.tar.gz", hash = "sha256:514bd33c30e0bf56b0ed44ee15e120d7e47b61ad908b2b1011da68c48a84ada9"}, + {file = "poetry_core-1.6.1-py3-none-any.whl", hash = "sha256:70707340447dee0e7f334f9495ae652481c67b32d8d218f296a376ac2ed73573"}, + {file = "poetry_core-1.6.1.tar.gz", hash = "sha256:0f9b0de39665f36d6594657e7d57b6f463cc10f30c28e6d1c3b9ff54c26c9ac3"}, ] [[package]] name = "poetry-plugin-export" -version = "1.3.0" +version = "1.4.0" description = "Poetry plugin to export the dependencies to various formats" -category = "dev" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "poetry_plugin_export-1.3.0-py3-none-any.whl", hash = "sha256:6e5919bf84afcb08cdd419a03f909f490d8671f00633a3c6df8ba09b0820dc2f"}, - {file = "poetry_plugin_export-1.3.0.tar.gz", hash = "sha256:61ae5ec1db233aba947a48e1ce54c6ff66afd0e1c87195d6bce64c73a5ae658c"}, + {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"}, ] [package.dependencies] -poetry = ">=1.3.0,<2.0.0" -poetry-core = ">=1.3.0,<2.0.0" +poetry = ">=1.5.0,<2.0.0" +poetry-core = ">=1.6.0,<2.0.0" [[package]] name = "prompt-toolkit" -version = "3.0.36" +version = "3.0.38" description = "Library for building powerful interactive command lines in Python" -category = "dev" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.36-py3-none-any.whl", hash = "sha256:aa64ad242a462c5ff0363a7b9cfe696c20d55d9fc60c11fd8e632d064804d305"}, - {file = "prompt_toolkit-3.0.36.tar.gz", hash = "sha256:3e163f254bef5a03b146397d7c1963bd3e2812f0964bb9a24e6ec761fd28db63"}, + {file = "prompt_toolkit-3.0.38-py3-none-any.whl", hash = "sha256:45ea77a2f7c60418850331366c81cf6b5b9cf4c7fd34616f733c5427e6abbb1f"}, + {file = "prompt_toolkit-3.0.38.tar.gz", hash = "sha256:23ac5d50538a9a38c8bde05fecb47d0b403ecd0662857a86f886f798563d5b9b"}, ] [package.dependencies] @@ -2456,26 +2364,25 @@ wcwidth = "*" [[package]] name = "psutil" -version = "5.9.4" +version = "5.9.5" description = "Cross-platform lib for process and system monitoring in Python." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"}, - {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"}, - {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"}, - {file = "psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"}, - {file = "psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"}, - {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"}, - {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"}, - {file = "psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"}, - {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"}, - {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"}, - {file = "psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"}, - {file = "psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"}, - {file = "psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"}, - {file = "psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"}, + {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"}, ] [package.extras] @@ -2485,7 +2392,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -2497,7 +2403,6 @@ files = [ name = "pure-eval" version = "0.2.2" description = "Safely evaluate AST nodes without side effects" -category = "dev" optional = false python-versions = "*" files = [ @@ -2510,39 +2415,36 @@ tests = ["pytest"] [[package]] name = "pybind11" -version = "2.10.3" +version = "2.10.4" description = "Seamless operability between C++11 and Python" -category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "pybind11-2.10.3-py3-none-any.whl", hash = "sha256:123e303f39ad5de97ddfa4f1f473cb85881a0a94ee5714eb3c37e2405371fc12"}, - {file = "pybind11-2.10.3.tar.gz", hash = "sha256:08cfe6d4f73746447cc85a400c8169a91608b8a00c5feecd8ff251a70565d12f"}, + {file = "pybind11-2.10.4-py3-none-any.whl", hash = "sha256:ec9be0c45061c829648d7e8c98a7d041768b768c934acd15196e0f1943d9a818"}, + {file = "pybind11-2.10.4.tar.gz", hash = "sha256:0bb621d3c45a049aa5923debb87c5c0e2668227905c55ebe8af722608d8ed927"}, ] [package.dependencies] -pybind11-global = {version = "2.10.3", optional = true, markers = "extra == \"global\""} +pybind11-global = {version = "2.10.4", optional = true, markers = "extra == \"global\""} [package.extras] -global = ["pybind11-global (==2.10.3)"] +global = ["pybind11-global (==2.10.4)"] [[package]] name = "pybind11-global" -version = "2.10.3" +version = "2.10.4" description = "Seamless operability between C++11 and Python" -category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "pybind11_global-2.10.3-py3-none-any.whl", hash = "sha256:0185118804f11349007989e9fab9d346b2d9997166b8ff90915419c528ba8690"}, - {file = "pybind11_global-2.10.3.tar.gz", hash = "sha256:9982149e0859e7a8496397b7dcdf083a37b87cbc1cac6e5dbe453eb3f3f22db1"}, + {file = "pybind11_global-2.10.4-py3-none-any.whl", hash = "sha256:2e8fef06c6f238ff437745221850047d9f987343c4a502b753a9fbd25215912e"}, + {file = "pybind11_global-2.10.4.tar.gz", hash = "sha256:210fbae7e0b1f02f137abf90fe3992b26b3eb173b91d5a892fc13c79f6fd54f4"}, ] [[package]] name = "pycodestyle" version = "2.8.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -2554,7 +2456,6 @@ files = [ name = "pycparser" version = "2.21" description = "C parser in Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2566,7 +2467,6 @@ files = [ name = "pydocstyle" version = "6.3.0" description = "Python docstring style checker" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2584,7 +2484,6 @@ toml = ["tomli (>=1.2.3)"] name = "pyflakes" version = "2.4.0" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2594,14 +2493,13 @@ files = [ [[package]] name = "pygments" -version = "2.14.0" +version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, - {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, + {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, + {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, ] [package.extras] @@ -2611,7 +2509,6 @@ plugins = ["importlib-metadata"] name = "pyparsing" version = "3.0.9" description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "dev" optional = false python-versions = ">=3.6.8" files = [ @@ -2622,11 +2519,24 @@ files = [ [package.extras] diagrams = ["jinja2", "railroad-diagrams"] +[[package]] +name = "pyproject-hooks" +version = "1.0.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"}, +] + +[package.dependencies] +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "pyrsistent" version = "0.19.3" description = "Persistent/Functional/Immutable data structures" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2661,18 +2571,16 @@ files = [ [[package]] name = "pytest" -version = "7.2.1" +version = "7.3.1" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, - {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, ] [package.dependencies] -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" @@ -2681,13 +2589,12 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-cov" version = "3.0.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2706,7 +2613,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2719,45 +2625,42 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2022.7.1" +version = "2023.3" description = "World timezone definitions, modern and historical" -category = "dev" optional = false python-versions = "*" files = [ - {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, - {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, + {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, + {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, ] [[package]] name = "pywin32" -version = "305" +version = "306" description = "Python for Window Extensions" -category = "dev" optional = false python-versions = "*" files = [ - {file = "pywin32-305-cp310-cp310-win32.whl", hash = "sha256:421f6cd86e84bbb696d54563c48014b12a23ef95a14e0bdba526be756d89f116"}, - {file = "pywin32-305-cp310-cp310-win_amd64.whl", hash = "sha256:73e819c6bed89f44ff1d690498c0a811948f73777e5f97c494c152b850fad478"}, - {file = "pywin32-305-cp310-cp310-win_arm64.whl", hash = "sha256:742eb905ce2187133a29365b428e6c3b9001d79accdc30aa8969afba1d8470f4"}, - {file = "pywin32-305-cp311-cp311-win32.whl", hash = "sha256:19ca459cd2e66c0e2cc9a09d589f71d827f26d47fe4a9d09175f6aa0256b51c2"}, - {file = "pywin32-305-cp311-cp311-win_amd64.whl", hash = "sha256:326f42ab4cfff56e77e3e595aeaf6c216712bbdd91e464d167c6434b28d65990"}, - {file = "pywin32-305-cp311-cp311-win_arm64.whl", hash = "sha256:4ecd404b2c6eceaca52f8b2e3e91b2187850a1ad3f8b746d0796a98b4cea04db"}, - {file = "pywin32-305-cp36-cp36m-win32.whl", hash = "sha256:48d8b1659284f3c17b68587af047d110d8c44837736b8932c034091683e05863"}, - {file = "pywin32-305-cp36-cp36m-win_amd64.whl", hash = "sha256:13362cc5aa93c2beaf489c9c9017c793722aeb56d3e5166dadd5ef82da021fe1"}, - {file = "pywin32-305-cp37-cp37m-win32.whl", hash = "sha256:a55db448124d1c1484df22fa8bbcbc45c64da5e6eae74ab095b9ea62e6d00496"}, - {file = "pywin32-305-cp37-cp37m-win_amd64.whl", hash = "sha256:109f98980bfb27e78f4df8a51a8198e10b0f347257d1e265bb1a32993d0c973d"}, - {file = "pywin32-305-cp38-cp38-win32.whl", hash = "sha256:9dd98384da775afa009bc04863426cb30596fd78c6f8e4e2e5bbf4edf8029504"}, - {file = "pywin32-305-cp38-cp38-win_amd64.whl", hash = "sha256:56d7a9c6e1a6835f521788f53b5af7912090674bb84ef5611663ee1595860fc7"}, - {file = "pywin32-305-cp39-cp39-win32.whl", hash = "sha256:9d968c677ac4d5cbdaa62fd3014ab241718e619d8e36ef8e11fb930515a1e918"}, - {file = "pywin32-305-cp39-cp39-win_amd64.whl", hash = "sha256:50768c6b7c3f0b38b7fb14dd4104da93ebced5f1a50dc0e834594bff6fbe1271"}, + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, ] [[package]] name = "pywin32-ctypes" version = "0.2.0" description = "" -category = "dev" optional = false python-versions = "*" files = [ @@ -2769,7 +2672,6 @@ files = [ name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2817,89 +2719,88 @@ files = [ [[package]] name = "pyzmq" -version = "25.0.0" +version = "25.1.0" description = "Python bindings for 0MQ" -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "pyzmq-25.0.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:2d05d904f03ddf1e0d83d97341354dfe52244a619b5a1440a5f47a5b3451e84e"}, - {file = "pyzmq-25.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a154ef810d44f9d28868be04641f837374a64e7449df98d9208e76c260c7ef1"}, - {file = "pyzmq-25.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:487305c2a011fdcf3db1f24e8814bb76d23bc4d2f46e145bc80316a59a9aa07d"}, - {file = "pyzmq-25.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e7b87638ee30ab13230e37ce5331b3e730b1e0dda30120b9eeec3540ed292c8"}, - {file = "pyzmq-25.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75243e422e85a62f0ab7953dc315452a56b2c6a7e7d1a3c3109ac3cc57ed6b47"}, - {file = "pyzmq-25.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:31e523d067ce44a04e876bed3ff9ea1ff8d1b6636d16e5fcace9d22f8c564369"}, - {file = "pyzmq-25.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8539216173135e9e89f6b1cc392e74e6b935b91e8c76106cf50e7a02ab02efe5"}, - {file = "pyzmq-25.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2754fa68da08a854f4816e05160137fa938a2347276471103d31e04bcee5365c"}, - {file = "pyzmq-25.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1bc30f0c18444d51e9b0d0dd39e3a4e7c53ee74190bebef238cd58de577ea9"}, - {file = "pyzmq-25.0.0-cp310-cp310-win32.whl", hash = "sha256:01d53958c787cfea34091fcb8ef36003dbb7913b8e9f8f62a0715234ebc98b70"}, - {file = "pyzmq-25.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:58fc3ad5e1cfd2e6d24741fbb1e216b388115d31b0ca6670f894187f280b6ba6"}, - {file = "pyzmq-25.0.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:e4bba04ea779a3d7ef25a821bb63fd0939142c88e7813e5bd9c6265a20c523a2"}, - {file = "pyzmq-25.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:af1fbfb7ad6ac0009ccee33c90a1d303431c7fb594335eb97760988727a37577"}, - {file = "pyzmq-25.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85456f0d8f3268eecd63dede3b99d5bd8d3b306310c37d4c15141111d22baeaf"}, - {file = "pyzmq-25.0.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0645b5a2d2a06fd8eb738018490c514907f7488bf9359c6ee9d92f62e844b76f"}, - {file = "pyzmq-25.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f72ea279b2941a5203e935a4588b9ba8a48aeb9a926d9dfa1986278bd362cb8"}, - {file = "pyzmq-25.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:4e295f7928a31ae0f657e848c5045ba6d693fe8921205f408ca3804b1b236968"}, - {file = "pyzmq-25.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ac97e7d647d5519bcef48dd8d3d331f72975afa5c4496c95f6e854686f45e2d9"}, - {file = "pyzmq-25.0.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:656281d496aaf9ca4fd4cea84e6d893e3361057c4707bd38618f7e811759103c"}, - {file = "pyzmq-25.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f6116991568aac48b94d6d8aaed6157d407942ea385335a6ed313692777fb9d"}, - {file = "pyzmq-25.0.0-cp311-cp311-win32.whl", hash = "sha256:0282bba9aee6e0346aa27d6c69b5f7df72b5a964c91958fc9e0c62dcae5fdcdc"}, - {file = "pyzmq-25.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:526f884a27e8bba62fe1f4e07c62be2cfe492b6d432a8fdc4210397f8cf15331"}, - {file = "pyzmq-25.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ccb3e1a863222afdbda42b7ca8ac8569959593d7abd44f5a709177d6fa27d266"}, - {file = "pyzmq-25.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4046d03100aca266e70d54a35694cb35d6654cfbef633e848b3c4a8d64b9d187"}, - {file = "pyzmq-25.0.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3100dddcada66ec5940ed6391ebf9d003cc3ede3d320748b2737553019f58230"}, - {file = "pyzmq-25.0.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7877264aa851c19404b1bb9dbe6eed21ea0c13698be1eda3784aab3036d1c861"}, - {file = "pyzmq-25.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:5049e75cc99db65754a3da5f079230fb8889230cf09462ec972d884d1704a3ed"}, - {file = "pyzmq-25.0.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:81f99fb1224d36eb91557afec8cdc2264e856f3464500b55749020ce4c848ef2"}, - {file = "pyzmq-25.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:a1cd4a95f176cdc0ee0a82d49d5830f13ae6015d89decbf834c273bc33eeb3d3"}, - {file = "pyzmq-25.0.0-cp36-cp36m-win32.whl", hash = "sha256:926236ca003aec70574754f39703528947211a406f5c6c8b3e50eca04a9e87fc"}, - {file = "pyzmq-25.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:94f0a7289d0f5c80807c37ebb404205e7deb737e8763eb176f4770839ee2a287"}, - {file = "pyzmq-25.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f3f96d452e9580cb961ece2e5a788e64abaecb1232a80e61deffb28e105ff84a"}, - {file = "pyzmq-25.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:930e6ad4f2eaac31a3d0c2130619d25db754b267487ebc186c6ad18af2a74018"}, - {file = "pyzmq-25.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e1081d7030a1229c8ff90120346fb7599b54f552e98fcea5170544e7c6725aab"}, - {file = "pyzmq-25.0.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:531866c491aee5a1e967c286cfa470dffac1e2a203b1afda52d62b58782651e9"}, - {file = "pyzmq-25.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fc7c1421c5b1c916acf3128bf3cc7ea7f5018b58c69a6866d70c14190e600ce9"}, - {file = "pyzmq-25.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9a2d5e419bd39a1edb6cdd326d831f0120ddb9b1ff397e7d73541bf393294973"}, - {file = "pyzmq-25.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:183e18742be3621acf8908903f689ec520aee3f08449bfd29f583010ca33022b"}, - {file = "pyzmq-25.0.0-cp37-cp37m-win32.whl", hash = "sha256:02f5cb60a7da1edd5591a15efa654ffe2303297a41e1b40c3c8942f8f11fc17c"}, - {file = "pyzmq-25.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:cac602e02341eaaf4edfd3e29bd3fdef672e61d4e6dfe5c1d065172aee00acee"}, - {file = "pyzmq-25.0.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:e14df47c1265356715d3d66e90282a645ebc077b70b3806cf47efcb7d1d630cb"}, - {file = "pyzmq-25.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:293a7c2128690f496057f1f1eb6074f8746058d13588389981089ec45d8fdc77"}, - {file = "pyzmq-25.0.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:731b208bc9412deeb553c9519dca47136b5a01ca66667cafd8733211941b17e4"}, - {file = "pyzmq-25.0.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b055a1cddf8035966ad13aa51edae5dc8f1bba0b5d5e06f7a843d8b83dc9b66b"}, - {file = "pyzmq-25.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17e1cb97d573ea84d7cd97188b42ca6f611ab3ee600f6a75041294ede58e3d20"}, - {file = "pyzmq-25.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:60ecbfe7669d3808ffa8a7dd1487d6eb8a4015b07235e3b723d4b2a2d4de7203"}, - {file = "pyzmq-25.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4c25c95416133942280faaf068d0fddfd642b927fb28aaf4ab201a738e597c1e"}, - {file = "pyzmq-25.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:be05504af0619d1cffa500af1e0ede69fb683f301003851f5993b5247cc2c576"}, - {file = "pyzmq-25.0.0-cp38-cp38-win32.whl", hash = "sha256:6bf3842af37af43fa953e96074ebbb5315f6a297198f805d019d788a1021dbc8"}, - {file = "pyzmq-25.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:b90bb8dfbbd138558f1f284fecfe328f7653616ff9a972433a00711d9475d1a9"}, - {file = "pyzmq-25.0.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:62b9e80890c0d2408eb42d5d7e1fc62a5ce71be3288684788f74cf3e59ffd6e2"}, - {file = "pyzmq-25.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:484c2c4ee02c1edc07039f42130bd16e804b1fe81c4f428e0042e03967f40c20"}, - {file = "pyzmq-25.0.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9ca6db34b26c4d3e9b0728841ec9aa39484eee272caa97972ec8c8e231b20c7e"}, - {file = "pyzmq-25.0.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:610d2d112acd4e5501fac31010064a6c6efd716ceb968e443cae0059eb7b86de"}, - {file = "pyzmq-25.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3594c0ff604e685d7e907860b61d0e10e46c74a9ffca168f6e9e50ea934ee440"}, - {file = "pyzmq-25.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c21a5f4e54a807df5afdef52b6d24ec1580153a6bcf0607f70a6e1d9fa74c5c3"}, - {file = "pyzmq-25.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4725412e27612f0d7d7c2f794d89807ad0227c2fc01dd6146b39ada49c748ef9"}, - {file = "pyzmq-25.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4d3d604fe0a67afd1aff906e54da557a5203368a99dcc50a70eef374f1d2abef"}, - {file = "pyzmq-25.0.0-cp39-cp39-win32.whl", hash = "sha256:3670e8c5644768f214a3b598fe46378a4a6f096d5fb82a67dfd3440028460565"}, - {file = "pyzmq-25.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:e99629a976809fe102ef73e856cf4b2660acd82a412a51e80ba2215e523dfd0a"}, - {file = "pyzmq-25.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:66509c48f7446b640eeae24b60c9c1461799a27b1b0754e438582e36b5af3315"}, - {file = "pyzmq-25.0.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c464cc508177c09a5a6122b67f978f20e2954a21362bf095a0da4647e3e908"}, - {file = "pyzmq-25.0.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:28bcb2e66224a7ac2843eb632e4109d6b161479e7a2baf24e37210461485b4f1"}, - {file = "pyzmq-25.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0e7ef9ac807db50b4eb6f534c5dcc22f998f5dae920cc28873d2c1d080a4fc9"}, - {file = "pyzmq-25.0.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:5050f5c50b58a6e38ccaf9263a356f74ef1040f5ca4030225d1cb1a858c5b7b6"}, - {file = "pyzmq-25.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2a73af6504e0d2805e926abf136ebf536735a13c22f709be7113c2ec65b4bec3"}, - {file = "pyzmq-25.0.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0e8d00228db627ddd1b418c7afd81820b38575f237128c9650365f2dd6ac3443"}, - {file = "pyzmq-25.0.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5605621f2181f20b71f13f698944deb26a0a71af4aaf435b34dd90146092d530"}, - {file = "pyzmq-25.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6136bfb0e5a9cf8c60c6ac763eb21f82940a77e6758ea53516c8c7074f4ff948"}, - {file = "pyzmq-25.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0a90b2480a26aef7c13cff18703ba8d68e181facb40f78873df79e6d42c1facc"}, - {file = "pyzmq-25.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00c94fd4c9dd3c95aace0c629a7fa713627a5c80c1819326b642adf6c4b8e2a2"}, - {file = "pyzmq-25.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20638121b0bdc80777ce0ec8c1f14f1ffec0697a1f88f0b564fa4a23078791c4"}, - {file = "pyzmq-25.0.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6f75b4b8574f3a8a0d6b4b52606fc75b82cb4391471be48ab0b8677c82f9ed4"}, - {file = "pyzmq-25.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cbb885f347eba7ab7681c450dee5b14aed9f153eec224ec0c3f299273d9241f"}, - {file = "pyzmq-25.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c48f257da280b3be6c94e05bd575eddb1373419dbb1a72c3ce64e88f29d1cd6d"}, - {file = "pyzmq-25.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:866eabf7c1315ef2e93e34230db7cbf672e0d7c626b37c11f7e870c8612c3dcc"}, - {file = "pyzmq-25.0.0.tar.gz", hash = "sha256:f330a1a2c7f89fd4b0aa4dcb7bf50243bf1c8da9a2f1efc31daf57a2046b31f2"}, + {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"}, ] [package.dependencies] @@ -2907,101 +2808,103 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "rapidfuzz" -version = "2.13.7" +version = "2.15.1" description = "rapid fuzzy string matching" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "rapidfuzz-2.13.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b75dd0928ce8e216f88660ab3d5c5ffe990f4dd682fd1709dba29d5dafdde6de"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24d3fea10680d085fd0a4d76e581bfb2b1074e66e78fd5964d4559e1fcd2a2d4"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8109e0324d21993d5b2d111742bf5958f3516bf8c59f297c5d1cc25a2342eb66"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f705652360d520c2de52bee11100c92f59b3e3daca308ebb150cbc58aecdad"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7496e8779905b02abc0ab4ba2a848e802ab99a6e20756ffc967a0de4900bd3da"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:24eb6b843492bdc63c79ee4b2f104059b7a2201fef17f25177f585d3be03405a"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:467c1505362823a5af12b10234cb1c4771ccf124c00e3fc9a43696512bd52293"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53dcae85956853b787c27c1cb06f18bb450e22cf57a4ad3444cf03b8ff31724a"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46b9b8aa09998bc48dd800854e8d9b74bc534d7922c1d6e1bbf783e7fa6ac29c"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1fbad8fb28d98980f5bff33c7842efef0315d42f0cd59082108482a7e6b61410"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:43fb8cb030f888c3f076d40d428ed5eb4331f5dd6cf1796cfa39c67bf0f0fc1e"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:b6bad92de071cbffa2acd4239c1779f66851b60ffbbda0e4f4e8a2e9b17e7eef"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d00df2e4a81ffa56a6b1ec4d2bc29afdcb7f565e0b8cd3092fece2290c4c7a79"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-win32.whl", hash = "sha256:2c836f0f2d33d4614c3fbaf9a1eb5407c0fe23f8876f47fd15b90f78daa64c34"}, - {file = "rapidfuzz-2.13.7-cp310-cp310-win_amd64.whl", hash = "sha256:c36fd260084bb636b9400bb92016c6bd81fd80e59ed47f2466f85eda1fc9f782"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b34e8c0e492949ecdd5da46a1cfc856a342e2f0389b379b1a45a3cdcd3176a6e"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:875d51b3497439a72e2d76183e1cb5468f3f979ab2ddfc1d1f7dde3b1ecfb42f"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ae33a72336059213996fe4baca4e0e4860913905c2efb7c991eab33b95a98a0a"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5585189b3d90d81ccd62d4f18530d5ac8972021f0aaaa1ffc6af387ff1dce75"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42085d4b154a8232767de8296ac39c8af5bccee6b823b0507de35f51c9cbc2d7"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:585206112c294e335d84de5d5f179c0f932837752d7420e3de21db7fdc476278"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f891b98f8bc6c9d521785816085e9657212621e93f223917fb8e32f318b2957e"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08590905a95ccfa43f4df353dcc5d28c15d70664299c64abcad8721d89adce4f"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b5dd713a1734574c2850c566ac4286594bacbc2d60b9170b795bee4b68656625"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:988f8f6abfba7ee79449f8b50687c174733b079521c3cc121d65ad2d38831846"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b3210869161a864f3831635bb13d24f4708c0aa7208ef5baac1ac4d46e9b4208"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f6fe570e20e293eb50491ae14ddeef71a6a7e5f59d7e791393ffa99b13f1f8c2"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6120f2995f5154057454c5de99d86b4ef3b38397899b5da1265467e8980b2f60"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-win32.whl", hash = "sha256:b20141fa6cee041917801de0bab503447196d372d4c7ee9a03721b0a8edf5337"}, - {file = "rapidfuzz-2.13.7-cp311-cp311-win_amd64.whl", hash = "sha256:ec55a81ac2b0f41b8d6fb29aad16e55417036c7563bad5568686931aa4ff08f7"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d005e058d86f2a968a8d28ca6f2052fab1f124a39035aa0523261d6baf21e1f"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe59a0c21a032024edb0c8e43f5dee5623fef0b65a1e3c1281836d9ce199af3b"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfc04f7647c29fb48da7a04082c34cdb16f878d3c6d098d62d5715c0ad3000c"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68a89bb06d5a331511961f4d3fa7606f8e21237467ba9997cae6f67a1c2c2b9e"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:effe182767d102cb65dfbbf74192237dbd22d4191928d59415aa7d7c861d8c88"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25b4cedf2aa19fb7212894ce5f5219010cce611b60350e9a0a4d492122e7b351"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3a9bd02e1679c0fd2ecf69b72d0652dbe2a9844eaf04a36ddf4adfbd70010e95"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5e2b3d020219baa75f82a4e24b7c8adcb598c62f0e54e763c39361a9e5bad510"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:cf62dacb3f9234f3fddd74e178e6d25c68f2067fde765f1d95f87b1381248f58"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:fa263135b892686e11d5b84f6a1892523123a00b7e5882eff4fbdabb38667347"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:fa4c598ed77f74ec973247ca776341200b0f93ec3883e34c222907ce72cb92a4"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-win32.whl", hash = "sha256:c2523f8180ebd9796c18d809e9a19075a1060b1a170fde3799e83db940c1b6d5"}, - {file = "rapidfuzz-2.13.7-cp37-cp37m-win_amd64.whl", hash = "sha256:5ada0a14c67452358c1ee52ad14b80517a87b944897aaec3e875279371a9cb96"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ca8a23097c1f50e0fdb4de9e427537ca122a18df2eead06ed39c3a0bef6d9d3a"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9be02162af0376d64b840f2fc8ee3366794fc149f1e06d095a6a1d42447d97c5"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af4f7c3c904ca709493eb66ca9080b44190c38e9ecb3b48b96d38825d5672559"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f50d1227e6e2a0e3ae1fb1c9a2e1c59577d3051af72c7cab2bcc430cb5e18da"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c71d9d512b76f05fa00282227c2ae884abb60e09f08b5ca3132b7e7431ac7f0d"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b52ac2626945cd21a2487aeefed794c14ee31514c8ae69b7599170418211e6f6"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca00fafd2756bc9649bf80f1cf72c647dce38635f0695d7ce804bc0f759aa756"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d248a109699ce9992304e79c1f8735c82cc4c1386cd8e27027329c0549f248a2"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c88adbcb933f6b8612f6c593384bf824e562bb35fc8a0f55fac690ab5b3486e5"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c8601a66fbfc0052bb7860d2eacd303fcde3c14e87fdde409eceff516d659e77"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:27be9c63215d302ede7d654142a2e21f0d34ea6acba512a4ae4cfd52bbaa5b59"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3dcffe1f3cbda0dc32133a2ae2255526561ca594f15f9644384549037b355245"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8450d15f7765482e86ef9be2ad1a05683cd826f59ad236ef7b9fb606464a56aa"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-win32.whl", hash = "sha256:460853983ab88f873173e27cc601c5276d469388e6ad6e08c4fd57b2a86f1064"}, - {file = "rapidfuzz-2.13.7-cp38-cp38-win_amd64.whl", hash = "sha256:424f82c35dbe4f83bdc3b490d7d696a1dc6423b3d911460f5493b7ffae999fd2"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c3fbe449d869ea4d0909fc9d862007fb39a584fb0b73349a6aab336f0d90eaed"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:16080c05a63d6042643ae9b6cfec1aefd3e61cef53d0abe0df3069b9d4b72077"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dbcf5371ea704759fcce772c66a07647751d1f5dbdec7818331c9b31ae996c77"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:114810491efb25464016fd554fdf1e20d390309cecef62587494fc474d4b926f"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99a84ab9ac9a823e7e93b4414f86344052a5f3e23b23aa365cda01393ad895bd"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81642a24798851b118f82884205fc1bd9ff70b655c04018c467824b6ecc1fabc"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3741cb0bf9794783028e8b0cf23dab917fa5e37a6093b94c4c2f805f8e36b9f"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:759a3361711586a29bc753d3d1bdb862983bd9b9f37fbd7f6216c24f7c972554"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1333fb3d603d6b1040e365dca4892ba72c7e896df77a54eae27dc07db90906e3"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:916bc2e6cf492c77ad6deb7bcd088f0ce9c607aaeabc543edeb703e1fbc43e31"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:23524635840500ce6f4d25005c9529a97621689c85d2f727c52eed1782839a6a"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:ebe303cd9839af69dd1f7942acaa80b1ba90bacef2e7ded9347fbed4f1654672"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fe56659ccadbee97908132135de4b875543353351e0c92e736b7c57aee298b5a"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-win32.whl", hash = "sha256:3f11a7eff7bc6301cd6a5d43f309e22a815af07e1f08eeb2182892fca04c86cb"}, - {file = "rapidfuzz-2.13.7-cp39-cp39-win_amd64.whl", hash = "sha256:e8914dad106dacb0775718e54bf15e528055c4e92fb2677842996f2d52da5069"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f7930adf84301797c3f09c94b9c5a9ed90a9e8b8ed19b41d2384937e0f9f5bd"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c31022d9970177f6affc6d5dd757ed22e44a10890212032fabab903fdee3bfe7"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f42b82f268689f429def9ecfb86fa65ceea0eaf3fed408b570fe113311bf5ce7"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b477b43ced896301665183a5e0faec0f5aea2373005648da8bdcb3c4b73f280"}, - {file = "rapidfuzz-2.13.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d63def9bbc6b35aef4d76dc740301a4185867e8870cbb8719ec9de672212fca8"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c66546e30addb04a16cd864f10f5821272a1bfe6462ee5605613b4f1cb6f7b48"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f799d1d6c33d81e983d3682571cc7d993ae7ff772c19b3aabb767039c33f6d1e"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d82f20c0060ffdaadaf642b88ab0aa52365b56dffae812e188e5bdb998043588"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:042644133244bfa7b20de635d500eb9f46af7097f3d90b1724f94866f17cb55e"}, - {file = "rapidfuzz-2.13.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:75c45dcd595f8178412367e302fd022860ea025dc4a78b197b35428081ed33d5"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3d8b081988d0a49c486e4e845a547565fee7c6e7ad8be57ff29c3d7c14c6894c"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16ffad751f43ab61001187b3fb4a9447ec2d1aedeff7c5bac86d3b95f9980cc3"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:020858dd89b60ce38811cd6e37875c4c3c8d7fcd8bc20a0ad2ed1f464b34dc4e"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cda1e2f66bb4ba7261a0f4c2d052d5d909798fca557cbff68f8a79a87d66a18f"}, - {file = "rapidfuzz-2.13.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b6389c50d8d214c9cd11a77f6d501529cb23279a9c9cafe519a3a4b503b5f72a"}, - {file = "rapidfuzz-2.13.7.tar.gz", hash = "sha256:8d3e252d4127c79b4d7c2ae47271636cbaca905c8bb46d80c7930ab906cf4b5c"}, + {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"}, ] [package.extras] @@ -3009,21 +2912,20 @@ full = ["numpy"] [[package]] name = "requests" -version = "2.28.2" +version = "2.31.0" description = "Python HTTP for Humans." -category = "dev" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.7" files = [ - {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, - {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] [package.dependencies] certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -3031,14 +2933,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-toolbelt" -version = "0.10.1" +version = "1.0.0" description = "A utility belt for advanced users of python-requests" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "requests-toolbelt-0.10.1.tar.gz", hash = "sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d"}, - {file = "requests_toolbelt-0.10.1-py2.py3-none-any.whl", hash = "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7"}, + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, ] [package.dependencies] @@ -3046,33 +2947,32 @@ requests = ">=2.0.1,<3.0.0" [[package]] name = "scipy" -version = "1.10.0" +version = "1.10.1" description = "Fundamental algorithms for scientific computing in Python" -category = "main" optional = false python-versions = "<3.12,>=3.8" files = [ - {file = "scipy-1.10.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:b901b423c91281a974f6cd1c36f5c6c523e665b5a6d5e80fcb2334e14670eefd"}, - {file = "scipy-1.10.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:16ba05d3d1b9f2141004f3f36888e05894a525960b07f4c2bfc0456b955a00be"}, - {file = "scipy-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:151f066fe7d6653c3ffefd489497b8fa66d7316e3e0d0c0f7ff6acca1b802809"}, - {file = "scipy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f9ea0a37aca111a407cb98aa4e8dfde6e5d9333bae06dfa5d938d14c80bb5c3"}, - {file = "scipy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:27e548276b5a88b51212b61f6dda49a24acf5d770dff940bd372b3f7ced8c6c2"}, - {file = "scipy-1.10.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:42ab8b9e7dc1ebe248e55f54eea5307b6ab15011a7883367af48dd781d1312e4"}, - {file = "scipy-1.10.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e096b062d2efdea57f972d232358cb068413dc54eec4f24158bcbb5cb8bddfd8"}, - {file = "scipy-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4df25a28bd22c990b22129d3c637fd5c3be4b7c94f975dca909d8bab3309b694"}, - {file = "scipy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ad449db4e0820e4b42baccefc98ec772ad7818dcbc9e28b85aa05a536b0f1a2"}, - {file = "scipy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:6faf86ef7717891195ae0537e48da7524d30bc3b828b30c9b115d04ea42f076f"}, - {file = "scipy-1.10.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:4bd0e3278126bc882d10414436e58fa3f1eca0aa88b534fcbf80ed47e854f46c"}, - {file = "scipy-1.10.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:38bfbd18dcc69eeb589811e77fae552fa923067fdfbb2e171c9eac749885f210"}, - {file = "scipy-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ab2a58064836632e2cec31ca197d3695c86b066bc4818052b3f5381bfd2a728"}, - {file = "scipy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd7a30970c29d9768a7164f564d1fbf2842bfc77b7d114a99bc32703ce0bf48"}, - {file = "scipy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:9b878c671655864af59c108c20e4da1e796154bd78c0ed6bb02bc41c84625686"}, - {file = "scipy-1.10.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:3afcbddb4488ac950ce1147e7580178b333a29cd43524c689b2e3543a080a2c8"}, - {file = "scipy-1.10.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:6e4497e5142f325a5423ff5fda2fff5b5d953da028637ff7c704378c8c284ea7"}, - {file = "scipy-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:441cab2166607c82e6d7a8683779cb89ba0f475b983c7e4ab88f3668e268c143"}, - {file = "scipy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0490dc499fe23e4be35b8b6dd1e60a4a34f0c4adb30ac671e6332446b3cbbb5a"}, - {file = "scipy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:954ff69d2d1bf666b794c1d7216e0a746c9d9289096a64ab3355a17c7c59db54"}, - {file = "scipy-1.10.0.tar.gz", hash = "sha256:c8b3cbc636a87a89b770c6afc999baa6bcbb01691b5ccbbc1b1791c7c0a07540"}, + {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"}, ] [package.dependencies] @@ -3087,7 +2987,6 @@ test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeo name = "secretstorage" version = "3.3.3" description = "Python bindings to FreeDesktop.org Secret Service API" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3099,28 +2998,10 @@ files = [ cryptography = ">=2.0" jeepney = ">=0.6" -[[package]] -name = "setuptools" -version = "67.3.2" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setuptools-67.3.2-py3-none-any.whl", hash = "sha256:bb6d8e508de562768f2027902929f8523932fcd1fb784e6d573d2cafac995a48"}, - {file = "setuptools-67.3.2.tar.gz", hash = "sha256:95f00380ef2ffa41d9bba85d95b27689d923c93dfbafed4aecd7cf988a25e012"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "shellingham" version = "1.5.0.post1" description = "Tool to Detect Surrounding Shell" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3132,7 +3013,6 @@ files = [ name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -3144,7 +3024,6 @@ files = [ name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3156,7 +3035,6 @@ files = [ name = "snowballstemmer" version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" optional = false python-versions = "*" files = [ @@ -3166,21 +3044,19 @@ files = [ [[package]] name = "soupsieve" -version = "2.4" +version = "2.4.1" description = "A modern CSS selector implementation for Beautiful Soup." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "soupsieve-2.4-py3-none-any.whl", hash = "sha256:49e5368c2cda80ee7e84da9dbe3e110b70a4575f196efb74e51b94549d921955"}, - {file = "soupsieve-2.4.tar.gz", hash = "sha256:e28dba9ca6c7c00173e34e4ba57448f0688bb681b7c5e8bf4971daafc093d69a"}, + {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"}, + {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"}, ] [[package]] name = "sphinx" version = "4.5.0" description = "Python documentation generator" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3214,14 +3090,13 @@ test = ["cython", "html5lib", "pytest", "pytest-cov", "typed-ast"] [[package]] name = "sphinx-rtd-theme" -version = "1.2.0" +version = "1.2.1" description = "Read the Docs theme for Sphinx" -category = "dev" 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.0-py2.py3-none-any.whl", hash = "sha256:f823f7e71890abe0ac6aaa6013361ea2696fc8d3e1fa798f463e82bdb77eeff2"}, - {file = "sphinx_rtd_theme-1.2.0.tar.gz", hash = "sha256:a0d8bd1a2ed52e0b338cbe19c4b2eef3c5e7a048769753dac6a9f059c7b641b8"}, + {file = "sphinx_rtd_theme-1.2.1-py2.py3-none-any.whl", hash = "sha256:2cc9351176cbf91944ce44cefd4fab6c3b76ac53aa9e15d6db45a3229ad7f866"}, + {file = "sphinx_rtd_theme-1.2.1.tar.gz", hash = "sha256:cf9a7dc0352cf179c538891cb28d6fad6391117d4e21c891776ab41dd6c8ff70"}, ] [package.dependencies] @@ -3236,7 +3111,6 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] name = "sphinx-tabs" version = "3.4.0" description = "Tabbed views for Sphinx" -category = "dev" optional = false python-versions = "~=3.7" files = [ @@ -3258,7 +3132,6 @@ testing = ["bs4", "coverage", "pygments", "pytest (>=7.1,<8)", "pytest-cov", "py name = "sphinxcontrib-applehelp" version = "1.0.4" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -3274,7 +3147,6 @@ test = ["pytest"] name = "sphinxcontrib-devhelp" version = "1.0.2" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -3290,7 +3162,6 @@ test = ["pytest"] name = "sphinxcontrib-htmlhelp" version = "2.0.1" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -3304,24 +3175,22 @@ test = ["html5lib", "pytest"] [[package]] name = "sphinxcontrib-jquery" -version = "2.0.0" +version = "4.1" description = "Extension to include jQuery on newer Sphinx releases" -category = "dev" optional = false python-versions = ">=2.7" files = [ - {file = "sphinxcontrib-jquery-2.0.0.tar.gz", hash = "sha256:8fb65f6dba84bf7bcd1aea1f02ab3955ac34611d838bcc95d4983b805b234daa"}, - {file = "sphinxcontrib_jquery-2.0.0-py3-none-any.whl", hash = "sha256:ed47fa425c338ffebe3c37e1cdb56e30eb806116b85f01055b158c7057fdb995"}, + {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, + {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, ] [package.dependencies] -setuptools = "*" +Sphinx = ">=1.8" [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -3336,7 +3205,6 @@ test = ["flake8", "mypy", "pytest"] name = "sphinxcontrib-qthelp" version = "1.0.3" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -3352,7 +3220,6 @@ test = ["pytest"] name = "sphinxcontrib-serializinghtml" version = "1.1.5" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -3368,7 +3235,6 @@ test = ["pytest"] name = "stack-data" version = "0.6.2" description = "Extract data from python stack frames and tracebacks for informative displays" -category = "dev" optional = false python-versions = "*" files = [ @@ -3386,14 +3252,13 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "stevedore" -version = "5.0.0" +version = "5.1.0" description = "Manage dynamic plugins for Python applications" -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "stevedore-5.0.0-py3-none-any.whl", hash = "sha256:bd5a71ff5e5e5f5ea983880e4a1dd1bb47f8feebbb3d95b592398e2f02194771"}, - {file = "stevedore-5.0.0.tar.gz", hash = "sha256:2c428d2338976279e8eb2196f7a94910960d9f7ba2f41f3988511e95ca447021"}, + {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, + {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, ] [package.dependencies] @@ -3403,7 +3268,6 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" name = "tinycss2" version = "1.2.1" description = "A tiny CSS parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3422,7 +3286,6 @@ test = ["flake8", "isort", "pytest"] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -3434,7 +3297,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3444,42 +3306,39 @@ files = [ [[package]] name = "tomlkit" -version = "0.11.6" +version = "0.11.8" description = "Style preserving TOML library" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"}, - {file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"}, + {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, + {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, ] [[package]] name = "tornado" -version = "6.2" +version = "6.3.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -category = "dev" optional = false -python-versions = ">= 3.7" +python-versions = ">= 3.8" files = [ - {file = "tornado-6.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72"}, - {file = "tornado-6.2-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca"}, - {file = "tornado-6.2-cp37-abi3-win32.whl", hash = "sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23"}, - {file = "tornado-6.2-cp37-abi3-win_amd64.whl", hash = "sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"}, - {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"}, + {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:c367ab6c0393d71171123ca5515c61ff62fe09024fa6bf299cd1339dc9456829"}, + {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b46a6ab20f5c7c1cb949c72c1994a4585d2eaa0be4853f50a03b5031e964fc7c"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2de14066c4a38b4ecbbcd55c5cc4b5340eb04f1c5e81da7451ef555859c833f"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05615096845cf50a895026f749195bf0b10b8909f9be672f50b0fe69cba368e4"}, + {file = "tornado-6.3.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b17b1cf5f8354efa3d37c6e28fdfd9c1c1e5122f2cb56dac121ac61baa47cbe"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:29e71c847a35f6e10ca3b5c2990a52ce38b233019d8e858b755ea6ce4dcdd19d"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:834ae7540ad3a83199a8da8f9f2d383e3c3d5130a328889e4cc991acc81e87a0"}, + {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6a0848f1aea0d196a7c4f6772197cbe2abc4266f836b0aac76947872cd29b411"}, + {file = "tornado-6.3.2-cp38-abi3-win32.whl", hash = "sha256:7efcbcc30b7c654eb6a8c9c9da787a851c18f8ccd4a5a3a95b05c7accfa068d2"}, + {file = "tornado-6.3.2-cp38-abi3-win_amd64.whl", hash = "sha256:0c325e66c8123c606eea33084976c832aa4e766b7dff8aedd7587ea44a604cdf"}, + {file = "tornado-6.3.2.tar.gz", hash = "sha256:4b927c4f19b71e627b13f3db2324e4ae660527143f9e1f2e2fb404f3a187e2ba"}, ] [[package]] name = "traceback2" version = "1.4.0" description = "Backports of the traceback module" -category = "dev" optional = false python-versions = "*" files = [ @@ -3494,7 +3353,6 @@ linecache2 = "*" name = "traitlets" version = "5.9.0" description = "Traitlets Python configuration system" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3508,21 +3366,30 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] [[package]] name = "trove-classifiers" -version = "2023.2.8" +version = "2023.5.24" description = "Canonical source for classifiers on PyPI (pypi.org)." -category = "dev" optional = false python-versions = "*" files = [ - {file = "trove-classifiers-2023.2.8.tar.gz", hash = "sha256:3b6960fb96c1d4cc9988bdc1b90bcd65fcf5d9843d884dfc86bd674ff81a4dea"}, - {file = "trove_classifiers-2023.2.8-py3-none-any.whl", hash = "sha256:3aff899dd9792c4d095740980a5967eb98094ff881faf0b29afc775b75aaaac6"}, + {file = "trove-classifiers-2023.5.24.tar.gz", hash = "sha256:fd5a1546283be941f47540a135bdeae8fb261380a6a204d9c18012f2a1b0ceae"}, + {file = "trove_classifiers-2023.5.24-py3-none-any.whl", hash = "sha256:d9d7ae14fb90bf3d50bef99c3941b176b5326509e6e9037e622562d6352629d0"}, +] + +[[package]] +name = "typing-extensions" +version = "4.6.3" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, + {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, ] [[package]] name = "unittest2" version = "1.1.0" description = "The new features in unittest backported to Python 2.4+." -category = "dev" optional = false python-versions = "*" files = [ @@ -3537,14 +3404,13 @@ traceback2 = "*" [[package]] name = "urllib3" -version = "1.26.14" +version = "1.26.16" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, - {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, + {file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"}, + {file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"}, ] [package.extras] @@ -3554,51 +3420,28 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" -version = "20.16.5" -description = "Virtual Python Environment builder" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "virtualenv-20.16.5-py3-none-any.whl", hash = "sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27"}, - {file = "virtualenv-20.16.5.tar.gz", hash = "sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da"}, -] - -[package.dependencies] -distlib = ">=0.3.5,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<3" - -[package.extras] -docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"] -testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] - -[[package]] -name = "virtualenv" -version = "20.19.0" +version = "20.23.0" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.19.0-py3-none-any.whl", hash = "sha256:54eb59e7352b573aa04d53f80fc9736ed0ad5143af445a1e539aada6eb947dd1"}, - {file = "virtualenv-20.19.0.tar.gz", hash = "sha256:37a640ba82ed40b226599c522d411e4be5edb339a0c0de030c0dc7b646d61590"}, + {file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"}, + {file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"}, ] [package.dependencies] distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<4" +filelock = ">=3.11,<4" +platformdirs = ">=3.2,<4" [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"] [[package]] name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -3610,7 +3453,6 @@ files = [ name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" -category = "dev" optional = false python-versions = "*" files = [ @@ -3622,7 +3464,6 @@ files = [ name = "xattr" version = "0.10.1" description = "Python wrapper for extended filesystem attributes" -category = "dev" optional = false python-versions = "*" files = [ @@ -3705,21 +3546,20 @@ cffi = ">=1.0" [[package]] name = "zipp" -version = "3.13.0" +version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.13.0-py3-none-any.whl", hash = "sha256:e8b2a36ea17df80ffe9e2c4fda3f693c3dad6df1697d3cd3af232db680950b0b"}, - {file = "zipp-3.13.0.tar.gz", hash = "sha256:23f70e964bc11a34cef175bc90ba2914e1e4545ea1e3e2f67c079671883f9cb6"}, + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "2.0" python-versions = ">=3.8, <3.11" -content-hash = "1c0d6bce699c6702d5b43f9987307e8cb6e415dc2340deaddb89606108e3a094" +content-hash = "1ddc2df45b167c409828188c9353936aec9c5738befb6bf612ff4f0a5d1a200e" diff --git a/pyproject.toml b/pyproject.toml index 45f2bfe4f..f1ef8af88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ packages = [ include = ["tutorials", "src/lava/magma/runtime/message_infrastructure/*.so", "src/lava/magma/runtime/message_infrastructure/install/lib/lib*"] -version = "0.6.0" +version = "0.7.0" description = "A Software Framework for Neuromorphic Computing" homepage = "https://lava-nc.org/" @@ -21,7 +21,7 @@ repository = "https://github.com/lava-nc/lava" authors = [ "Intel's Neuromorphic Computing Lab and the open source community " ] -license = "Lava uses multiple licenses and is licensed under BSD-3-Clause or LGPL-2.1-or-later" +license = "(BSD-3-Clause), (LGPL-2.1-or-later)" keywords = [ "neuromorphic", "ai", @@ -37,8 +37,8 @@ classifiers = [ "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", - "License :: OSI Approved :: The 3-Clause BSD License (BSD-3-Clause)", - "License :: OSI Approved :: GNU Lesser General Public License v2.1 or later (LGPL-2.1-or-later)", + "License :: OSI Approved :: BSD License", + "License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)", "Operating System :: OS Independent" ] @@ -86,7 +86,7 @@ sphinx_rtd_theme = { extras = ["toml"], version = "^1.0.0" } autopep8 = "^1.6.0" ipykernel = "^6.15.0" nbformat = "^5.3.0" -nbconvert = "^7.2.0" +nbconvert = ">=7.2.10, <7.3" cpplint = "^1.6.0" psutil = "^5.9.4" @@ -181,11 +181,11 @@ pep8-naming = ["-*"] # mccabe = ["+*"] # pep8-naming = ["+*"] # pyflakes = ["+*"] -# pylint = ["+*"] +pylint = ["+*"] pycodestyle = ["+*", "-W503", "-E203"] -pyflakes = ["-*"] # Disable temporarily until lint fix is pushed -pylint = ["-*"] # Disable temporarily until lint fix is pushed +# pyflakes = ["-*"] # Disable temporarily until lint fix is pushed +# pylint = ["-*"] # Disable temporarily until lint fix is pushed [tool.flakeheaven.exceptions."tests/"] pycodestyle = ["-F401"] # Disable a check diff --git a/src/lava/magma/compiler/builders/channel_builder.py b/src/lava/magma/compiler/builders/channel_builder.py index d6db0366d..21d1d1a58 100644 --- a/src/lava/magma/compiler/builders/channel_builder.py +++ b/src/lava/magma/compiler/builders/channel_builder.py @@ -174,4 +174,3 @@ def build( Exception Can't build channel of type specified """ - pass diff --git a/src/lava/magma/compiler/builders/interfaces.py b/src/lava/magma/compiler/builders/interfaces.py index eed2c90fc..5c78fbf01 100644 --- a/src/lava/magma/compiler/builders/interfaces.py +++ b/src/lava/magma/compiler/builders/interfaces.py @@ -14,7 +14,6 @@ class AbstractBuilder(ABC): @abstractmethod def build(self): """Build the actual process.""" - pass class ResourceAddress(ABC): @@ -24,7 +23,6 @@ class ResourceAddress(ABC): class Resource(ABC): def write(self, hw: ty.Any): """Given hw, write this compiled resource""" - pass class CompiledResource(Resource): diff --git a/src/lava/magma/compiler/builders/py_builder.py b/src/lava/magma/compiler/builders/py_builder.py index afb67ec23..785f591cd 100644 --- a/src/lava/magma/compiler/builders/py_builder.py +++ b/src/lava/magma/compiler/builders/py_builder.py @@ -5,6 +5,7 @@ import typing as ty import numpy as np +from scipy.sparse import csr_matrix from lava.magma.compiler.builders.interfaces import AbstractProcessBuilder from lava.magma.runtime.message_infrastructure import ( @@ -392,6 +393,12 @@ def build(self): var[:] = v.value elif issubclass(lt.cls, (int, float, str)): var = v.value + elif issubclass(lt.cls, (csr_matrix)): + if isinstance(v.value, int): + var = csr_matrix(v.shape, dtype=lt.d_type) + var[:] = v.value + else: + var = v.value else: raise NotImplementedError( "Cannot initiliaze variable " diff --git a/src/lava/magma/compiler/channel_map.py b/src/lava/magma/compiler/channel_map.py index 79039cd0a..2eadd52cc 100644 --- a/src/lava/magma/compiler/channel_map.py +++ b/src/lava/magma/compiler/channel_map.py @@ -85,8 +85,9 @@ def from_proc_groups(self, the list of process groups given as input. """ port_pairs = self._get_port_pairs_from_proc_groups(proc_groups) - default_payload = Payload(multiplicity=1) - channel_map = ChannelMap.fromkeys(port_pairs, default_payload) + channel_map = ChannelMap() + for port_pair in port_pairs: + channel_map[port_pair] = Payload(multiplicity=1) return channel_map @classmethod diff --git a/src/lava/magma/compiler/compiler.py b/src/lava/magma/compiler/compiler.py index ae2e0f628..bc09e3bb0 100644 --- a/src/lava/magma/compiler/compiler.py +++ b/src/lava/magma/compiler/compiler.py @@ -132,7 +132,7 @@ def compile( proc_builders, channel_map = self._compile_proc_groups( proc_groups, channel_map ) - py_builders, c_builders, nc_builders = split_proc_builders_by_type( + _, c_builders, nc_builders = split_proc_builders_by_type( proc_builders ) diff --git a/src/lava/magma/compiler/compiler_graphs.py b/src/lava/magma/compiler/compiler_graphs.py index 7d36fc140..75a112e62 100644 --- a/src/lava/magma/compiler/compiler_graphs.py +++ b/src/lava/magma/compiler/compiler_graphs.py @@ -8,7 +8,6 @@ import itertools import os import pkgutil -import re import sys import types import typing as ty diff --git a/src/lava/magma/compiler/mapper.py b/src/lava/magma/compiler/mapper.py index 2f570877f..d0d957faf 100644 --- a/src/lava/magma/compiler/mapper.py +++ b/src/lava/magma/compiler/mapper.py @@ -76,7 +76,7 @@ def map_cores(self, executable: Executable, executable: Compiled Executable """ - py_builders, c_builders, nc_builders = split_proc_builders_by_type( + _, c_builders, nc_builders = split_proc_builders_by_type( executable.proc_builders) # Iterate over all the ncbuilder and map them for ncb in nc_builders.values(): @@ -124,7 +124,6 @@ def map_cores(self, executable: Executable, # src or dst and its initializers for port_pair in channel_map: src = port_pair.src - dst = port_pair.dst # Checking if the initializers are same if channel_map[port_pair].src_port_initializer == ports[ port]: diff --git a/src/lava/magma/compiler/node.py b/src/lava/magma/compiler/node.py index 20e0c7261..88a9d5647 100644 --- a/src/lava/magma/compiler/node.py +++ b/src/lava/magma/compiler/node.py @@ -4,7 +4,6 @@ from __future__ import annotations -import typing import typing as ty from collections import UserList, OrderedDict @@ -27,7 +26,7 @@ def __init__( processes: ty.List[AbstractProcess], ): self.id: int = -1 - self.node_type: typing.Type[AbstractNode] = node_type + self.node_type: ty.Type[AbstractNode] = node_type self.processes = processes def add_process(self, process: AbstractProcess): @@ -57,7 +56,7 @@ def __str__(self): result.append(str(self.node_map)) return "\n".join(result) - def append(self, node: Node): + def append(self, node: Node): # pylint: disable=arguments-renamed """Appends a new node to the NodeConfig.""" node.id = self._node_ctr self._node_ctr += 1 diff --git a/src/lava/magma/compiler/subcompilers/channel_builders_factory.py b/src/lava/magma/compiler/subcompilers/channel_builders_factory.py index a2e04671c..a47c4777f 100644 --- a/src/lava/magma/compiler/subcompilers/channel_builders_factory.py +++ b/src/lava/magma/compiler/subcompilers/channel_builders_factory.py @@ -106,10 +106,10 @@ def from_channel_map( src_pt_init.connected_port_type = LoihiConnectedPortType.C_PY dst_pt_init.connected_port_type = LoihiConnectedPortType.C_PY if ch_type is ChannelType.PyC: - p_port, c_port = src_port, dst_port + p_port = src_port pi = dst_pt_init else: - c_port, p_port = src_port, dst_port + p_port = dst_port pi = src_pt_init lt = getattr(p_port.process.model_class, p_port.name).cls if lt in [PyInPort.VEC_DENSE, PyOutPort.VEC_DENSE]: diff --git a/src/lava/magma/compiler/subcompilers/interfaces.py b/src/lava/magma/compiler/subcompilers/interfaces.py index 067c6da02..63147ca30 100644 --- a/src/lava/magma/compiler/subcompilers/interfaces.py +++ b/src/lava/magma/compiler/subcompilers/interfaces.py @@ -20,14 +20,12 @@ class AbstractSubCompiler(ABC): def compile(self, channel_map: ChannelMap) -> ChannelMap: """Partitions all Processes in the SubCompiler's ProcGroup onto the available resources.""" - pass @abstractmethod def get_builders( self, channel_map: ChannelMap ) -> ty.Tuple[ty.Dict[AbstractProcess, AbstractProcessBuilder], ChannelMap]: """After compilation, creates and returns builders for all Processes.""" - pass class SubCompiler(AbstractSubCompiler): diff --git a/src/lava/magma/compiler/utils.py b/src/lava/magma/compiler/utils.py index 8070683f9..994b2aeb0 100644 --- a/src/lava/magma/compiler/utils.py +++ b/src/lava/magma/compiler/utils.py @@ -142,7 +142,6 @@ class LoihiIOPortInitializer(LoihiPortInitializer): @dataclass class LoihiInPortInitializer(LoihiIOPortInitializer): """Port Initializer for a InPort for C/NC Models""" - pass @dataclass @@ -154,7 +153,6 @@ class LoihiCInPortInitializer(LoihiIOPortInitializer): @dataclass class LoihiOutPortInitializer(LoihiIOPortInitializer): """Port Initializer for a OutPort for C/NC Models""" - pass @dataclass diff --git a/src/lava/magma/compiler/var_model.py b/src/lava/magma/compiler/var_model.py index eff1af8f2..805ed5b14 100644 --- a/src/lava/magma/compiler/var_model.py +++ b/src/lava/magma/compiler/var_model.py @@ -68,6 +68,7 @@ def __post_init__(self, var: Var) -> None: self.name: str = var.name self.shape: ty.Tuple[int, ...] = var.shape self.proc_id: int = var.process.id + self.dtype = type(var.init) @dataclass diff --git a/src/lava/magma/core/learning/constants.py b/src/lava/magma/core/learning/constants.py index 0ec3bdbb2..ab34c9cb9 100644 --- a/src/lava/magma/core/learning/constants.py +++ b/src/lava/magma/core/learning/constants.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: BSD-3-Clause # See: https://spdx.org/licenses/ -from enum import IntEnum, auto +from enum import IntEnum import lava.magma.core.learning.string_symbols as str_symbols # --------------------------------------------------------------------------- @@ -89,7 +89,8 @@ class GradedSpikeCfg(IntEnum): - USE_REGULAR_IMPULSE = auto() - OVERWRITE = auto() - ADD_WITH_SATURATION = auto() - ADD_WITHOUT_SATURATION = auto() + # Do not change the values below as they determine hardware behavior + USE_REGULAR_IMPULSE = 0 + OVERWRITE = 1 + ADD_WITH_SATURATION = 2 + ADD_WITHOUT_SATURATION = 3 diff --git a/src/lava/magma/core/learning/symbolic_equation.py b/src/lava/magma/core/learning/symbolic_equation.py index d3d72a78c..1ccbc9fe0 100644 --- a/src/lava/magma/core/learning/symbolic_equation.py +++ b/src/lava/magma/core/learning/symbolic_equation.py @@ -3,14 +3,14 @@ # See: https://spdx.org/licenses/ import re -from abc import abstractmethod +from abc import ABC, abstractmethod import typing as ty import ast import lava.magma.core.learning.string_symbols as str_symbols -class Symbol(object): +class Symbol(ABC): """Super class for all possible symbols.""" def __init__(self, expr: ty.Optional[str] = "") -> None: @@ -50,8 +50,9 @@ def __str__(self): pass @staticmethod - def find_expr(expr: str, reg_expr: str, symbol: "Symbol") \ - -> ty.Tuple[ty.Optional["Symbol"], str]: + def find_expr(expr: str, + reg_expr: str, + symbol: "Symbol") -> ty.Tuple[ty.Optional["Symbol"], str]: """Factory method for creating symbols. Matches an expression to a regular expression and if there is a match, @@ -132,7 +133,6 @@ def __str__(self) -> str: class Operator(Symbol): """Abstract super class for operator Symbols.""" - pass class Addition(Operator): @@ -231,8 +231,6 @@ def __str__(self): class FactorSym(Symbol): """Abstract super class for factor Symbols.""" - pass - class Dependency(FactorSym): """Abstract super class for dependency Symbols.""" diff --git a/src/lava/magma/core/learning/utils.py b/src/lava/magma/core/learning/utils.py index 5b7d6998c..480860397 100644 --- a/src/lava/magma/core/learning/utils.py +++ b/src/lava/magma/core/learning/utils.py @@ -4,7 +4,6 @@ import numpy as np import typing as ty -import struct def stochastic_round(values: np.ndarray, diff --git a/src/lava/magma/core/model/interfaces.py b/src/lava/magma/core/model/interfaces.py index f878a02b0..cf00a438a 100644 --- a/src/lava/magma/core/model/interfaces.py +++ b/src/lava/magma/core/model/interfaces.py @@ -27,7 +27,6 @@ def shape(self) -> ty.Tuple[int, ...]: @abstractmethod def csp_ports(self) -> ty.List[AbstractTransferPort]: """Returns all csp ports of the port.""" - pass def start(self): """Start all csp ports.""" diff --git a/src/lava/magma/core/model/py/connection.py b/src/lava/magma/core/model/py/connection.py index 5c59dea96..dfa33c440 100644 --- a/src/lava/magma/core/model/py/connection.py +++ b/src/lava/magma/core/model/py/connection.py @@ -3,8 +3,10 @@ # See: https://spdx.org/licenses/ from abc import abstractmethod +from lava.utils.sparse import find import numpy as np import typing +from scipy.sparse import csr_matrix from lava.magma.core.learning.learning_rule import ( LoihiLearningRule, @@ -305,7 +307,7 @@ def _create_learning_rule_applier( pass @abstractmethod - def _init_randoms(self): + def _init_randoms(self) -> None: pass @property @@ -827,11 +829,12 @@ def _compute_trace_histories(self) -> typing.Tuple[np.ndarray, np.ndarray]: t_spike_y = self.ty # most naive algorithm to decay traces - x_traces_history = np.full((t_epoch + 1,) + x_traces.shape, np.nan, + x_traces_history = np.full((t_epoch + 1,) + x_traces.shape, 0, dtype=int) x_traces_history[0] = x_traces - y_traces_history = np.full((t_epoch + 1,) + y_traces.shape, np.nan, + y_traces_history = np.full((t_epoch + 1,) + y_traces.shape, 0, dtype=int) + y_traces_history[0] = y_traces for t in range(1, t_epoch + 1): @@ -942,10 +945,16 @@ def _apply_learning_rules( for syn_var_name, lr_applier in self._learning_rule_appliers.items(): syn_var = getattr(self, syn_var_name).copy() - syn_var = np.left_shift( - syn_var, W_ACCUMULATOR_S - W_SYN_VAR_S[syn_var_name] - ) - syn_var = lr_applier.apply(syn_var, **applier_args) + shift = W_ACCUMULATOR_S - W_SYN_VAR_S[syn_var_name] + if isinstance(syn_var, csr_matrix): + syn_var.data = syn_var.data << shift + dst, src, _ = find(syn_var, explicit_zeros=True) + syn_var[dst, src] = lr_applier.apply(syn_var, + **applier_args)[dst, src] + else: + syn_var = syn_var << shift + syn_var = lr_applier.apply(syn_var, **applier_args) + syn_var = self._saturate_synaptic_variable_accumulator( syn_var_name, syn_var ) @@ -954,9 +963,11 @@ def _apply_learning_rules( syn_var, self._conn_var_random.random_stochastic_round, ) - syn_var = np.right_shift( - syn_var, W_ACCUMULATOR_S - W_SYN_VAR_S[syn_var_name] - ) + + if isinstance(syn_var, csr_matrix): + syn_var.data = syn_var.data >> shift + else: + syn_var = syn_var >> shift syn_var = self._saturate_synaptic_variable(syn_var_name, syn_var) setattr(self, syn_var_name, syn_var) @@ -1015,83 +1026,93 @@ def _extract_applier_args( return applier_args def _saturate_synaptic_variable_accumulator( - self, synaptic_variable_name: str, - synaptic_variable_values: np.ndarray - ) -> np.ndarray: + self, syn_var_name: str, + syn_var_values: typing.Union[np.ndarray, csr_matrix] + ) -> typing.Union[np.ndarray, csr_matrix]: """Saturate synaptic variable accumulator. Checks that sign is valid. Parameters ---------- - synaptic_variable_name: str + syn_var_name: str Synaptic variable name. - synaptic_variable_values: ndarray + syn_var_values: ndarray, csr_matrix Synaptic variable values to saturate. Returns ---------- - result : ndarray + result : ndarray, csr_matrix Saturated synaptic variable values. """ # Weights - if synaptic_variable_name == "weights": + if syn_var_name == "weights": if self.sign_mode == SignMode.MIXED: - return synaptic_variable_values + return syn_var_values elif self.sign_mode == SignMode.EXCITATORY: - return np.maximum(0, synaptic_variable_values) + return np.maximum(0, syn_var_values) elif self.sign_mode == SignMode.INHIBITORY: - return np.minimum(0, synaptic_variable_values) + return np.minimum(0, syn_var_values) # Delays - elif synaptic_variable_name == "tag_2": - return np.maximum(0, synaptic_variable_values) + elif syn_var_name == "tag_2": + if isinstance(syn_var_values, csr_matrix): + syn_var_values.data[syn_var_values.data < 0] = 0 + return syn_var_values + return np.maximum(0, syn_var_values) # Tags - elif synaptic_variable_name == "tag_1": - return synaptic_variable_values + elif syn_var_name == "tag_1": + return syn_var_values else: raise ValueError( - f"synaptic_variable_name can be 'weights', " + f"syn_var_name can be 'weights', " f"'tag_1', or 'tag_2'." - f"Got {synaptic_variable_name=}." + f"Got {syn_var_name=}." ) @staticmethod def _stochastic_round_synaptic_variable( - synaptic_variable_name: str, - synaptic_variable_values: np.ndarray, + syn_var_name: str, + syn_var_values: typing.Union[np.ndarray, csr_matrix], random: float, - ) -> np.ndarray: + ) -> typing.Union[np.ndarray, csr_matrix]: """Stochastically round synaptic variable after learning rule application. Parameters ---------- - synaptic_variable_name: str + syn_var_name: str Synaptic variable name. - synaptic_variable_values: ndarray + syn_var_values: ndarray, csr_matrix Synaptic variable values to stochastically round. Returns ---------- - result : ndarray + result : ndarray, csr_matrix Stochastically rounded synaptic variable values. """ - exp_mant = 2 ** (W_ACCUMULATOR_U - W_SYN_VAR_U[synaptic_variable_name]) + exp_mant = 2 ** (W_ACCUMULATOR_U - W_SYN_VAR_U[syn_var_name]) - integer_part = synaptic_variable_values / exp_mant + if isinstance(syn_var_values, csr_matrix): + integer_part = syn_var_values.data / exp_mant + else: + integer_part = syn_var_values / exp_mant fractional_part = integer_part % 1 integer_part = np.floor(integer_part) integer_part = stochastic_round(integer_part, random, fractional_part) - result = (integer_part * exp_mant).astype( - synaptic_variable_values.dtype - ) - return result + if isinstance(syn_var_values, csr_matrix): + syn_var_values.data = (integer_part + * exp_mant).astype(syn_var_values.dtype) + return syn_var_values + else: + return (integer_part * exp_mant).astype( + syn_var_values.dtype + ) def _saturate_synaptic_variable( - self, synaptic_variable_name: str, - synaptic_variable_values: np.ndarray + self, syn_var_name: str, + syn_var_val: typing.Union[np.ndarray, csr_matrix] ) -> np.ndarray: """Saturate synaptic variable. @@ -1100,40 +1121,54 @@ def _saturate_synaptic_variable( Parameters ---------- - synaptic_variable_name: str + syn_var_name: str Synaptic variable name. - synaptic_variable_values: ndarray + syn_var_val: ndarray, csr_matrix Synaptic variable values to saturate. Returns ---------- - result : ndarray + result : ndarray, csr_matrix Saturated synaptic variable values. """ + # Weights - if synaptic_variable_name == "weights": + if syn_var_name == "weights": return clip_weights( - synaptic_variable_values, + syn_var_val, sign_mode=self.sign_mode, num_bits=W_WEIGHTS_U, ) # Delays - elif synaptic_variable_name == "tag_2": + elif syn_var_name == "tag_2": + if isinstance(syn_var_val, csr_matrix): + _min = -(2 ** W_TAG_2_U) - 1 + _max = (2 ** W_TAG_2_U) - 1 + syn_var_val.data[syn_var_val.data < _min] = _min + syn_var_val.data[syn_var_val.data > _max] = _max + return syn_var_val + return np.clip( - synaptic_variable_values, a_min=0, a_max=2 ** W_TAG_2_U - 1 + syn_var_val, a_min=0, a_max=2 ** W_TAG_2_U - 1 ) # Tags - elif synaptic_variable_name == "tag_1": + elif syn_var_name == "tag_1": + if isinstance(syn_var_val, csr_matrix): + _min = -(2 ** W_TAG_1_U) - 1 + _max = (2 ** W_TAG_1_U) - 1 + syn_var_val.data[syn_var_val.data < _min] = _min + syn_var_val.data[syn_var_val.data > _max] = _max + return syn_var_val return np.clip( - synaptic_variable_values, + syn_var_val, a_min=-(2 ** W_TAG_1_U) - 1, a_max=2 ** W_TAG_1_U - 1, ) else: raise ValueError( - f"synaptic_variable_name can be 'weights', " + f"syn_var_name can be 'weights', " f"'tag_1', or 'tag_2'." - f"Got {synaptic_variable_name=}." + f"Got {syn_var_name=}." ) @@ -1423,7 +1458,12 @@ def _apply_learning_rules( for syn_var_name, lr_applier in self._learning_rule_appliers.items(): syn_var = getattr(self, syn_var_name).copy() - syn_var = lr_applier.apply(syn_var, **applier_args) + if (isinstance(syn_var, csr_matrix)): + dst, src, _ = find(syn_var, explicit_zeros=True) + syn_var[dst, src] = lr_applier.apply(syn_var, + **applier_args)[dst, src] + else: + syn_var = lr_applier.apply(syn_var, **applier_args) syn_var = self._saturate_synaptic_variable(syn_var_name, syn_var) setattr(self, syn_var_name, syn_var) @@ -1511,6 +1551,9 @@ def _saturate_synaptic_variable( elif synaptic_variable_name == "tag_1": return synaptic_variable_values elif synaptic_variable_name == "tag_2": + if isinstance(synaptic_variable_values, csr_matrix): + synaptic_variable_values[synaptic_variable_values < 0] = 0 + return synaptic_variable_values return np.maximum(0, synaptic_variable_values) else: raise ValueError( @@ -1518,3 +1561,6 @@ def _saturate_synaptic_variable( f"'tag_1', or 'tag_2'." f"Got {synaptic_variable_name=}." ) + + def _init_randoms(self) -> None: + pass diff --git a/src/lava/magma/core/model/py/model.py b/src/lava/magma/core/model/py/model.py index fb2623d29..443e317bb 100644 --- a/src/lava/magma/core/model/py/model.py +++ b/src/lava/magma/core/model/py/model.py @@ -6,7 +6,9 @@ from abc import ABC, abstractmethod # from functools import partial import logging +from lava.utils.sparse import find import numpy as np +from scipy.sparse import csr_matrix import platform from lava.magma.runtime.message_infrastructure import (SendPort, @@ -77,10 +79,9 @@ def __setattr__(self, key: str, value: ty.Any): """ self.__dict__[key] = value - if isinstance(value, AbstractPyPort): + if isinstance(value, AbstractPyPort) and value not in self.py_ports: self.py_ports.append(value) - # Store all VarPorts for efficient RefPort -> VarPort handling - if isinstance(value, PyVarPort): + if isinstance(value, PyVarPort) and value not in self.var_ports: self.var_ports.append(value) def start(self): @@ -120,11 +121,14 @@ def _get_var(self): addr_path = self.service_to_process.recv() data_port = getTempSendPort(str(addr_path[0])) data_port.start() - if isinstance(var, int) or isinstance(var, np.integer): + if isinstance(var, int) or isinstance(var, np.int32): data_port.send(enum_to_np(var)) elif isinstance(var, np.ndarray): # FIXME: send a whole vector (also runtime_service.py) data_port.send(var) + elif isinstance(var, csr_matrix): + _, _, data = find(var, explicit_zeros=True) + data_port.send(data) elif isinstance(var, str): data_port.send(np.array(var, dtype=str)) data_port.join() @@ -132,7 +136,7 @@ def _get_var(self): data_port = self.process_to_service # Header corresponds to number of values # Data is either send once (for int) or one by one (array) - if isinstance(var, int) or isinstance(var, np.integer): + if isinstance(var, int) or isinstance(var, np.int32): data_port.send(enum_to_np(1)) data_port.send(enum_to_np(var)) elif isinstance(var, np.ndarray): @@ -142,6 +146,12 @@ def _get_var(self): data_port.send(enum_to_np(num_items)) for value in var_iter: data_port.send(enum_to_np(value, np.float64)) + elif isinstance(var, csr_matrix): + _, _, values = find(var, explicit_zeros=True) + num_items = var.data.size + data_port.send(enum_to_np(num_items)) + for value in values: + data_port.send(enum_to_np(value, np.float64)) elif isinstance(var, str): encoded_str = list(var.encode("ascii")) data_port.send(enum_to_np(len(encoded_str))) @@ -162,7 +172,7 @@ def _set_var(self): self.process_to_service.send(np.array([addr_path])) buffer = data_port.recv() data_port.join() - if isinstance(var, int) or isinstance(var, np.integer): + if isinstance(var, int) or isinstance(var, np.int32): buffer = buffer[0] if isinstance(var, int): setattr(self, var_name, buffer.item()) @@ -173,6 +183,11 @@ def _set_var(self): var_iter = np.nditer(var, op_flags=['readwrite']) setattr(self, var_name, buffer.astype(var.dtype)) self.process_to_service.send(MGMT_RESPONSE.SET_COMPLETE) + elif isinstance(var, csr_matrix): + dst, src, _ = find(var) + var = csr_matrix((buffer, (dst, src)), var.shape) + setattr(self, var_name, var) + self.process_to_service.send(MGMT_RESPONSE.SET_COMPLETE) elif isinstance(var, str): setattr(self, var_name, np.array_str(buffer)) self.process_to_service.send(MGMT_RESPONSE.SET_COMPLETE) @@ -181,7 +196,7 @@ def _set_var(self): raise RuntimeError("Unsupported type") else: data_port = self.service_to_process - if isinstance(var, int) or isinstance(var, np.integer): + if isinstance(var, int) or isinstance(var, np.int32): # First item is number of items (1) - not needed data_port.recv() # Data to set @@ -202,6 +217,18 @@ def _set_var(self): num_items -= 1 i[...] = data_port.recv()[0] self.process_to_service.send(MGMT_RESPONSE.SET_COMPLETE) + elif isinstance(var, csr_matrix): + # First item is number of items + num_items = int(data_port.recv()[0]) + + buffer = np.empty(num_items) + # Set data one by one + for i in range(num_items): + buffer[i] = data_port.recv()[0] + dst, src, _ = find(var) + var = csr_matrix((buffer, (dst, src)), var.shape) + setattr(self, var_name, var) + self.process_to_service.send(MGMT_RESPONSE.SET_COMPLETE) elif isinstance(var, str): # First item is number of items num_items = int(data_port.recv()[0]) @@ -221,9 +248,6 @@ def _set_var(self): # notify PM that Vars have been changed self.on_var_update() - # notify PM that Vars have been changed - self.on_var_update() - def _handle_var_port(self, var_port): """Handles read/write requests on the given VarPort.""" var_port.service() @@ -241,7 +265,7 @@ def run(self): if cmd in self._cmd_handlers: self._cmd_handlers[cmd]() if cmd == MGMT_COMMAND.STOP[0] or self._stopped: - break + return else: raise ValueError( f"Illegal RuntimeService command! ProcessModels of " @@ -264,7 +288,6 @@ def add_ports_for_polling(self): """ Add various ports to poll for communication on ports """ - pass def join(self): """ @@ -279,7 +302,6 @@ def on_var_update(self): """This method is called if a Var is updated. It can be used as callback function to calculate dependent changes.""" - pass class PyLoihiProcessModel(AbstractPyProcessModel): diff --git a/src/lava/magma/core/model/py/ports.py b/src/lava/magma/core/model/py/ports.py index 8d83d8429..933eeaef2 100644 --- a/src/lava/magma/core/model/py/ports.py +++ b/src/lava/magma/core/model/py/ports.py @@ -55,7 +55,6 @@ def csp_ports(self) -> ty.List[AbstractTransferPort]: ------- A list of all CSP Ports connected to the PyPort. """ - pass class AbstractPyIOPort(AbstractPyPort): @@ -703,13 +702,19 @@ def read(self) -> np.ndarray: The value of the referenced Var. """ if self._csp_send_port and self._csp_recv_port: - header = np.ones(self._shape, dtype=self._d_type) * \ - VarPortCmd.GET.astype(self._d_type) - self._csp_send_port.send(header) + if not hasattr(self, 'get_header'): + # pylint: disable=W0201 + self.get_header = (np.ones(self._csp_send_port.shape, + dtype=self._d_type) + * VarPortCmd.GET.astype(self._d_type)) + self._csp_send_port.send(self.get_header) return self._transformer.transform(self._csp_recv_port.recv(), self._csp_recv_port) - - return np.zeros(self._shape, self._d_type) + else: + if not hasattr(self, 'get_zeros'): + # pylint: disable=W0201 + self.get_zeros = np.zeros(self._shape, self._d_type) + return self.get_zeros def write(self, data: np.ndarray): """Abstract method to write data to a VarPort to set the value of the @@ -721,9 +726,12 @@ def write(self, data: np.ndarray): The data to send via _csp_send_port. """ if self._csp_send_port: - header = np.ones(self._shape, dtype=data.dtype) * \ - VarPortCmd.SET.astype(self._d_type) - self._csp_send_port.send(header) + if not hasattr(self, 'set_header'): + # pylint: disable=W0201 + self.set_header = (np.ones(self._csp_send_port.shape, + dtype=data.dtype) + * VarPortCmd.SET.astype(self._d_type)) + self._csp_send_port.send(self.set_header) self._csp_send_port.send(data) diff --git a/src/lava/magma/core/process/ports/ports.py b/src/lava/magma/core/process/ports/ports.py index 083394d9f..d0094adf3 100644 --- a/src/lava/magma/core/process/ports/ports.py +++ b/src/lava/magma/core/process/ports/ports.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: BSD-3-Clause # See: https://spdx.org/licenses/ +from __future__ import annotations import typing as ty from abc import ABC, abstractmethod import math @@ -383,8 +384,6 @@ class AbstractIOPort(AbstractPort): type hierarchy needed for validating connections. """ - pass - class AbstractRVPort(AbstractPort): """Abstract base class for RefPorts and VarPorts. @@ -392,8 +391,6 @@ class AbstractRVPort(AbstractPort): type hierarchy needed for validating connections. """ - pass - class AbstractSrcPort(ABC): """Interface for source ports such as OutPorts and RefPorts from which @@ -402,8 +399,6 @@ class AbstractSrcPort(ABC): type hierarchy needed for validating connections. """ - pass - class AbstractDstPort(ABC): """Interface for destination ports such as InPorts and VarPorts in which @@ -412,8 +407,6 @@ class AbstractDstPort(ABC): type hierarchy needed for validating connections. """ - pass - class OutPort(AbstractIOPort, AbstractSrcPort): """Output ports are members of a Lava Process and can be connected to @@ -635,7 +628,7 @@ def get_dst_vars(self) -> ty.List[Var]: return [ty.cast(VarPort, p).var for p in self.get_dst_ports()] @staticmethod - def create_implicit_var_port(var: Var) -> "ImplicitVarPort": + def create_implicit_var_port(var: Var) -> ImplicitVarPort: """Creates and returns an ImplicitVarPort for the given Var.""" # Create a VarPort to wrap Var vp = ImplicitVarPort(var) @@ -646,9 +639,12 @@ def create_implicit_var_port(var: Var) -> "ImplicitVarPort": vp.process = var.process # VarPort name could shadow existing attribute if hasattr(var.process, vp.name): - raise AssertionError( - "Name of implicit VarPort might conflict" - " with existing attribute.") + name = str(vp.name) + name_suffix = 1 + while hasattr(var.process, vp.name): + # pylint: disable=W0201 + vp.name = name + "_" + str(name_suffix) + name_suffix += 1 setattr(var.process, vp.name, vp) var.process.var_ports.add_members({vp.name: vp}) @@ -749,7 +745,9 @@ def connect_from( class ImplicitVarPort(VarPort): """Sub class for VarPort to identify implicitly created VarPorts when a RefPort connects directly to a Var.""" - pass + + def __init__(self, var: Var) -> None: + super().__init__(var) class AbstractVirtualPort(AbstractPort): @@ -826,7 +824,7 @@ class ReshapePort(AbstractVirtualPort): def __init__(self, new_shape: ty.Tuple[int, ...], old_shape: ty.Tuple[int, ...]): - AbstractPort.__init__(self, new_shape) + super().__init__(new_shape) self.old_shape = old_shape def get_transform_func_fwd(self) -> ft.partial: @@ -861,7 +859,7 @@ class ConcatPort(AbstractVirtualPort): tensor-valued data array from the derived to the new shape.""" def __init__(self, ports: ty.List[AbstractPort], axis: int): - AbstractPort.__init__(self, self._get_new_shape(ports, axis)) + super().__init__(self._get_new_shape(ports, axis)) self._connect_backward( ports, AbstractPort, assert_same_shape=False, assert_same_type=True ) @@ -916,7 +914,7 @@ def __init__(self, new_shape: ty.Tuple[int, ...], axes: ty.Tuple[int, ...]): self.axes = axes - AbstractPort.__init__(self, new_shape) + super().__init__(new_shape) def get_transform_func_fwd(self) -> ft.partial: """Returns a function pointer that implements the forward (fwd) @@ -941,18 +939,3 @@ def get_transform_func_bwd(self) -> ft.partial: function_pointer : functools.partial a function pointer that can be applied to incoming data""" return ft.partial(np.transpose, axes=np.argsort(self.axes)) - - -class ReIndexPort(AbstractVirtualPort): - """A ReIndexPort is a virtual port that allows to re-index the elements - of a port before connecting to another port. - It is used by the compiler to map the indices of the underlying - tensor-valued data array from the derived to the new shape. - - Example: - out_port = OutPort((2, 2)) - in_port = InPort((2, 2)) - out_port.reindex([3, 1, 0, 2]).connect(in_port) - """ - - pass diff --git a/src/lava/magma/core/process/ports/reduce_ops.py b/src/lava/magma/core/process/ports/reduce_ops.py index 4d9e99ad7..709d77367 100644 --- a/src/lava/magma/core/process/ports/reduce_ops.py +++ b/src/lava/magma/core/process/ports/reduce_ops.py @@ -9,11 +9,7 @@ class AbstractReduceOp(ABC): """Reduce operations are required by InPorts to specify how date from multiple OutPorts connected to the same InPorts gets integrated.""" - pass - class ReduceSum(AbstractReduceOp): """ReduceOp to indicate that multiple inputs to same InPort should be added.""" - - pass diff --git a/src/lava/magma/core/process/process.py b/src/lava/magma/core/process/process.py index 808df52b7..51047b5cc 100644 --- a/src/lava/magma/core/process/process.py +++ b/src/lava/magma/core/process/process.py @@ -19,7 +19,6 @@ from lava.magma.core.run_conditions import AbstractRunCondition from lava.magma.core.run_configs import RunConfig from lava.magma.runtime.runtime import Runtime -from lava.magma.runtime.runtime_services.enums import LoihiVersion if ty.TYPE_CHECKING: from lava.magma.core.model.model import AbstractProcessModel @@ -224,7 +223,6 @@ def __del__(self): def __enter__(self): """Executed when Process enters a "with" block of a context manager.""" - pass def __exit__(self, exc_type, exc_val, exc_tb): """Stop the runtime when exiting "with" block of a context manager.""" @@ -284,7 +282,7 @@ def runtime(self, value): def register_sub_procs(self, procs: ty.Dict[str, AbstractProcess]): """Registers other processes as sub processes of this process.""" - for name, p in procs.items(): + for p in procs.values(): if not isinstance(p, AbstractProcess): raise AssertionError p.parent_proc = self @@ -331,6 +329,9 @@ def run(self, being no longer satisfied, run() can be called again to resume execution from the current state. + NOTE: run_cfg will be ignored when re-running a previously compiled + process. + Parameters ---------- condition : AbstractRunCondition @@ -344,18 +345,37 @@ def run(self, """ if not self._runtime: if not run_cfg: - raise ValueError("The Processes that are to be executed have " - "not been compiled yet. This requires that a" - "RunConfig is passed to the run() method.") + raise ValueError("run_cfg must not be None when calling" + " Process.run() unless the process has already" + " been compiled.") + self.create_runtime(run_cfg, compile_config) + self._runtime.start(condition) - executable = self.compile(run_cfg, compile_config) - self._runtime = Runtime(executable, - ActorType.MultiProcessing, - loglevel=self._log_config.level) - executable.assign_runtime_to_all_processes(self._runtime) - self._runtime.initialize() + def create_runtime(self, run_cfg: RunConfig, + compile_config: + ty.Optional[ty.Dict[str, ty.Any]] = None): + """Creates a runtime for this process and all connected processes by + compiling the process to an executable and assigning that executable to + the process and connected processes. - self._runtime.start(condition) + See Process.run() for information on Process blocking, which must be + specified in the run_cfg passed to create_runtime. + + Parameters + ---------- + run_cfg : RunConfig, optional + Used by the compiler to select a ProcessModel for each Process. + Must be provided when Processes have to be compiled, can be + omitted otherwise. + compile_config: Dict[str, Any], optional + Configuration options for the Compiler and SubCompilers. + """ + executable = self.compile(run_cfg, compile_config) + self._runtime = Runtime(executable, + ActorType.MultiProcessing, + loglevel=self._log_config.level) + executable.assign_runtime_to_all_processes(self._runtime) + self._runtime.initialize() def compile(self, run_cfg: RunConfig, diff --git a/src/lava/magma/core/process/variable.py b/src/lava/magma/core/process/variable.py index e8457d1b1..aed95a66d 100644 --- a/src/lava/magma/core/process/variable.py +++ b/src/lava/magma/core/process/variable.py @@ -4,7 +4,8 @@ import typing as ty import numpy as np - +from scipy.sparse import csr_matrix, spmatrix +from lava.utils.sparse import find from lava.magma.core.process.interfaces import ( AbstractProcessMember, IdGeneratorSingleton, @@ -127,7 +128,9 @@ def validate_alias(self): f"." ) - def set(self, value: ty.Union[np.ndarray, str], idx: np.ndarray = None): + def set(self, + value: ty.Union[np.ndarray, str, spmatrix], + idx: np.ndarray = None): """Sets value of Var. If this Var aliases another Var, then set(..) is delegated to aliased Var.""" if self.aliased_var is not None: @@ -142,6 +145,19 @@ def set(self, value: ty.Union[np.ndarray, str], idx: np.ndarray = None): value = np.array( list(value.encode("ascii")), dtype=np.int32 ) + elif isinstance(value, spmatrix): + value = value.tocsr() + init_dst, init_src, init_val = find(self.init, + explicit_zeros=True) + dst, src, val = find(value, explicit_zeros=True) + if value.shape != self.init.shape or \ + np.any(init_dst != dst) or \ + np.any(init_src != src) or \ + len(val) != len(init_val): + raise ValueError("Indices and number of non-zero " + "elements must stay equal when using" + "set on a sparse matrix.") + value = val self.process.runtime.set_var(self.id, value, idx) else: raise ValueError( @@ -155,7 +171,7 @@ def get(self, idx: np.ndarray = None) -> np.ndarray: if self.aliased_var is not None: return self.aliased_var.get(idx) else: - if self.process.runtime: + if self.process and self.process.runtime: buffer = self.process.runtime.get_var(self.id, idx) if isinstance(self.init, str): if SupportTempChannel: @@ -164,6 +180,10 @@ def get(self, idx: np.ndarray = None) -> np.ndarray: # decode if var is string return bytes(buffer.astype(int).tolist()). \ decode("ascii") + if isinstance(self.init, csr_matrix): + dst, src, _ = find(self.init) + ret = csr_matrix((buffer, (dst, src)), self.init.shape) + return ret else: return buffer else: diff --git a/src/lava/magma/core/resources.py b/src/lava/magma/core/resources.py index 28bc102e7..3419ae1b8 100644 --- a/src/lava/magma/core/resources.py +++ b/src/lava/magma/core/resources.py @@ -13,89 +13,73 @@ class AbstractResource(ABC): Each ProcessModel lists its required hardware resources with the @requires decorator. """ - pass # Compute resources ------------------------------------------------------------ class AbstractComputeResource(AbstractResource): """A compute resource, for example a particular type of neuromorphic processor or CPU.""" - pass class CPU(AbstractComputeResource): """A central processing unit on a regular computer or laptop.""" - pass class HostCPU(AbstractComputeResource): """A central processing unit on a special host system that holds neuromorphic devices.""" - pass class GPU(AbstractComputeResource): """A graphical processing unit.""" - pass class ECPU(AbstractComputeResource): """An embedded central processing unit that is part of a neuromorphic chip.""" - pass class LMT(ECPU): """A Lakemont embedded central processing unit.""" - pass class PB(ECPU): """A Powell Bute embedded central processing unit.""" - pass class NeuroCore(AbstractComputeResource): """A neuromorphic core.""" - pass class Loihi1NeuroCore(NeuroCore): """A neuromorphic core on a Loihi 1 chip.""" - pass class Loihi2NeuroCore(NeuroCore): """A neuromorphic core on a Loihi 2 chip.""" - pass # Peripheral resources --------------------------------------------------------- class AbstractPeripheralResource(AbstractResource): """A hardware resource that is a peripheral device.""" - pass class DVS(AbstractPeripheralResource): """An event-based dynamic vision sensor (DVS).""" - pass class HardDrive(AbstractPeripheralResource): """A hard drive in a computer.""" - pass class HeadNodeHardDrive(AbstractPeripheralResource): """A hard drive attached to a HeadNode (the node on which a user executes code).""" - pass # Nodes ------------------------------------------------------------------------ class AbstractNode(ABC): """A node is a resource that has other compute or peripheral resources.""" - pass class GenericNode(AbstractNode): @@ -112,7 +96,6 @@ class HeadNode(GenericNode): class Loihi1System(AbstractNode): """A neuromorphic system that carries Loihi 1 chips.""" - pass class KapohoBay(Loihi1System): @@ -133,7 +116,6 @@ class Pohoiki(Loihi1System): class Loihi2System(AbstractNode): """A neuromorphic system that carries Loihi 2 chips.""" - pass class OheoGulch(Loihi2System): diff --git a/src/lava/magma/core/run_configs.py b/src/lava/magma/core/run_configs.py index f7144ce4d..1bf6ffda0 100644 --- a/src/lava/magma/core/run_configs.py +++ b/src/lava/magma/core/run_configs.py @@ -79,11 +79,9 @@ def __init__(self, def exclude_nodes(self, nodes: ty.List[AbstractNode]): """Excludes given nodes from consideration by compiler.""" - pass def require_nodes(self, nodes: ty.List[AbstractNode]): """Requires that compiler maps processes to given nodes.""" - pass def select(self, process: AbstractProcess, @@ -168,7 +166,7 @@ def __init__(self, self.exception_proc_model_map = {} def select(self, - proc: AbstractProcess, + process: AbstractProcess, proc_models: ty.List[ty.Type[AbstractProcessModel]]) \ -> ty.Type[AbstractProcessModel]: """ @@ -177,7 +175,7 @@ def select(self, Parameters ---------- - proc: AbstractProcess + process: AbstractProcess Process for which ProcessModel is selected proc_models: List[AbstractProcessModel] List of ProcessModels to select from @@ -191,9 +189,10 @@ def select(self, # ------------------------------ # Raise error if num_pm == 0: - raise AssertionError(f"[{self.__class__.__qualname__}]: No " - f"ProcessModels exist for Process " - f"{proc.name}::{proc.__class__.__qualname__}.") + raise AssertionError( + f"[{self.__class__.__qualname__}]: No ProcessModels exist for " + f"Process {process.name}::{process.__class__.__qualname__}." + ) # Required modules and helper functions from lava.magma.core.model.sub.model import AbstractSubProcessModel @@ -206,8 +205,8 @@ def _issubpm(pm: ty.Type[AbstractProcessModel]) -> bool: # ---------------------------- # We will simply return the ProcessModel class associated with a # Process class in the exceptions dictionary - if proc.__class__ in self.exception_proc_model_map: - return self.exception_proc_model_map[proc.__class__] + if process.__class__ in self.exception_proc_model_map: + return self.exception_proc_model_map[process.__class__] # Case 2: Only 1 PM found: # ----------------------- @@ -247,8 +246,8 @@ def _issubpm(pm: ty.Type[AbstractProcessModel]) -> bool: f"[{self.__class__.__qualname__}]: No " f"ProcessModels found with tag " f"'{self.select_tag}' for Process " - f"{proc.name}::" - f"{proc.__class__.__qualname__}.") + f"{process.name}::" + f"{process.__class__.__qualname__}.") # Case 3: Multiple PMs exist: # -------------------------- @@ -269,11 +268,13 @@ def _issubpm(pm: ty.Type[AbstractProcessModel]) -> bool: # Assumption: User doesn't care about tags. We return the first # SubProcessModel found if self.select_tag is None: - self.log.info(f"[{self.__class__.__qualname__}]: Using the" - f" first SubProcessModel " - f"{proc_models[sub_pm_idxs[0]].__qualname__} " - f"available for Process " - f"{proc.name}::{proc.__class__.__qualname__}.") + self.log.info( + f"[{self.__class__.__qualname__}]: Using the first " + f"SubProcessModel " + f"{proc_models[sub_pm_idxs[0]].__qualname__} " + f"available for Process " + f"{process.name}::{process.__class__.__qualname__}." + ) return proc_models[sub_pm_idxs[0]] # Case 3a(iii): User asked for a specific tag: # ------------------------------------------- @@ -286,8 +287,8 @@ def _issubpm(pm: ty.Type[AbstractProcessModel]) -> bool: raise AssertionError(f"[{self.__class__.__qualname__}]: No " f"ProcessModels found with tag " f"{self.select_tag} for Process " - f"{proc.name}::" - f"{proc.__class__.__qualname__}.") + f"{process.name}::" + f"{process.__class__.__qualname__}.") return proc_models[valid_sub_pm_idxs[0]] # Case 3b: User didn't ask for SubProcessModel: # -------------------------------------------- @@ -295,8 +296,8 @@ def _issubpm(pm: ty.Type[AbstractProcessModel]) -> bool: if len(leaf_pm_idxs) == 0: raise AssertionError(f"[{self.__class__.__qualname__}]: " f"No hardware-specific ProcessModels were " - f"found for Process {proc.name}::" - f"{proc.__class__.__qualname__}. " + f"found for Process {process.name}::" + f"{process.__class__.__qualname__}. " f"Try setting select_sub_proc_model=True.") # Case 3b(i): User didn't provide select_tag: # ------------------------------------------ @@ -307,7 +308,7 @@ def _issubpm(pm: ty.Type[AbstractProcessModel]) -> bool: f"Hardware-specific ProcessModel " f"{proc_models[leaf_pm_idxs[0]].__qualname__} " f"available for Process " - f"{proc.name}::{proc.__class__.__qualname__}.") + f"{process.name}::{process.__class__.__qualname__}.") return proc_models[leaf_pm_idxs[0]] # Case 3b(ii): User asked for a specific tag: # ------------------------------------------ @@ -320,8 +321,8 @@ def _issubpm(pm: ty.Type[AbstractProcessModel]) -> bool: raise AssertionError(f"[{self.__class__.__qualname__}]: No " f"ProcessModels found with tag " f"'{self.select_tag}' for Process " - f"{proc.name}::" - f"{proc.__class__.__qualname__}.") + f"{process.name}::" + f"{process.__class__.__qualname__}.") return proc_models[valid_leaf_pm_idxs[0]] def _is_hw_supported(self, pm: ty.Type[AbstractProcessModel]) -> bool: diff --git a/src/lava/magma/runtime/message_infrastructure/factory.py b/src/lava/magma/runtime/message_infrastructure/factory.py index 750b029db..362a37e12 100644 --- a/src/lava/magma/runtime/message_infrastructure/factory.py +++ b/src/lava/magma/runtime/message_infrastructure/factory.py @@ -6,14 +6,13 @@ from lava.magma.runtime.message_infrastructure import PURE_PYTHON_VERSION -"""Factory class to create the messaging infrastructure""" - - class MessageInfrastructureFactory: """Creates the message infrastructure instance based on type""" @staticmethod def create(factory_type: ActorType): + """Creates the message infrastructure instance based on type + of actor framework being chosen.""" if PURE_PYTHON_VERSION: factory_type = ActorType.PyMultiProcessing """type of actor framework being chosen""" diff --git a/src/lava/magma/runtime/message_infrastructure/message_infrastructure_interface.py b/src/lava/magma/runtime/message_infrastructure/message_infrastructure_interface.py index 7d83169f4..f68a52428 100644 --- a/src/lava/magma/runtime/message_infrastructure/message_infrastructure_interface.py +++ b/src/lava/magma/runtime/message_infrastructure/message_infrastructure_interface.py @@ -7,15 +7,12 @@ from lava.magma.runtime.message_infrastructure import Channel from lava.magma.runtime.message_infrastructure.interfaces import ChannelType -"""A Message Infrastructure Interface which can create actors which would -participate in message passing/exchange, start and stop them as well as -declare the underlying Channel Infrastructure Class to be used for message -passing implementation.""" - class MessageInfrastructureInterface(ABC): - """Interface to provide the ability to create actors which can - communicate via message passing""" + """A Message Infrastructure Interface which can create actors which would + participate in message passing/exchange, start and stop them as well as + declare the underlying Channel Infrastructure Class to be used for message + passing implementation.""" @abstractmethod def init(self): @@ -25,7 +22,6 @@ def init(self): @abstractmethod def start(self): """Starts the messaging infrastructure""" - pass def pre_stop(self): """Stop MessageInfrastructure before join ports""" @@ -38,7 +34,6 @@ def stop(self): @abstractmethod def build_actor(self, target_fn: ty.Callable, builder): """Given a target_fn starts a system process""" - pass def cleanup(self, block=False): """Close all resources""" @@ -52,11 +47,9 @@ def trace(self, logger) -> int: @abstractmethod def actors(self) -> ty.List[ty.Any]: """Returns a list of actors""" - pass @abstractmethod def channel(self, channel_type: ChannelType, src_name, dst_name, shape, dtype, size, sync=False) -> Channel: """Given the Channel Type, Return the Channel Implementation to be used during execution""" - pass diff --git a/src/lava/magma/runtime/message_infrastructure/nx.py b/src/lava/magma/runtime/message_infrastructure/nx.py index 0d52f5145..604358785 100644 --- a/src/lava/magma/runtime/message_infrastructure/nx.py +++ b/src/lava/magma/runtime/message_infrastructure/nx.py @@ -27,21 +27,17 @@ class NxBoardMsgInterface(MessageInfrastructureInterface): @property def actors(self): """Returns a list of actors""" - pass def start(self): """Starts the shared memory manager""" - pass def build_actor(self, target_fn: ty.Callable, builder: ty.Union[ ty.Dict['AbstractProcess', 'PyProcessBuilder'], ty.Dict[ SyncDomain, 'RuntimeServiceBuilder']]) -> ty.Any: """Given a target_fn starts a system (os) process""" - pass def stop(self): """Stops the shared memory manager""" - pass def channel_class(self, channel_type: ChannelType) -> ty.Type[Channel]: """Given a channel type, returns the shared memory based class diff --git a/src/lava/magma/runtime/message_infrastructure/pypychannel.py b/src/lava/magma/runtime/message_infrastructure/pypychannel.py index 16906590b..1d5bd8601 100644 --- a/src/lava/magma/runtime/message_infrastructure/pypychannel.py +++ b/src/lava/magma/runtime/message_infrastructure/pypychannel.py @@ -8,6 +8,9 @@ from queue import Queue, Empty from threading import BoundedSemaphore, Condition, Thread from time import time +from scipy.sparse import csr_matrix +from lava.utils.sparse import find + import numpy as np from lava.magma.runtime.message_infrastructure import Channel @@ -61,7 +64,7 @@ def __init__(self, name, shm, proto, size, req, ack): self._done = False self._array = [] self._semaphore = None - self.observer = None + self.observer: ty.Optional[ty.Callable[[], ty.Any]] = None self.thread = None @property @@ -125,6 +128,10 @@ def send(self, data): """ if data.shape != self._shape: raise AssertionError(f"{data.shape=} {self._shape=} Mismatch") + + if isinstance(data, csr_matrix): + data = find(data, explicit_zeros=True)[2] + self._semaphore.acquire() self._array[self._idx][:] = data[:] self._idx = (self._idx + 1) % self._size @@ -203,7 +210,7 @@ def __init__(self, name, shm, proto, size, req, ack): self._done = False self._array = [] self._queue = None - self.observer = None + self.observer: ty.Optional[ty.Callable[[], ty.Any]] = None self.thread = None @property @@ -279,7 +286,6 @@ def recv(self): result = self._array[self._idx].copy() self._idx = (self._idx + 1) % self._size self._ack.release() - return result def join(self): @@ -304,26 +310,29 @@ def _changed(self): with self._cv: self._cv.notify_all() - def _set_observer(self, channel_actions, observer): + @staticmethod + def _set_observer( + channel_actions: ty.Tuple, + observer: ty.Union[ty.Callable[[], ty.Any], None]) -> None: for channel, _ in channel_actions: channel.observer = observer def select( self, - *args: ty.Tuple[ + *channel_actions: ty.Tuple[ ty.Union[SendPort, RecvPort], ty.Callable[[], ty.Any] ], - ): + ) -> None: """ Wait for any channel to become ready, then execute the corresponding callable and return the result. """ with self._cv: - self._set_observer(args, self._changed) + self._set_observer(channel_actions, self._changed) while True: - for channel, action in args: + for channel, action in channel_actions: if channel.probe(): - self._set_observer(args, None) + self._set_observer(channel_actions, None) return action() self._cv.wait() diff --git a/src/lava/magma/runtime/mgmt_token_enums.py b/src/lava/magma/runtime/mgmt_token_enums.py index 3c789cd74..bb0795fdf 100644 --- a/src/lava/magma/runtime/mgmt_token_enums.py +++ b/src/lava/magma/runtime/mgmt_token_enums.py @@ -2,12 +2,12 @@ # SPDX-License-Identifier: LGPL 2.1 or later # See: https://spdx.org/licenses/ +"""Defines message tokens for Actions (Commands) and Responses. Also defines +helper functions to convert scalar values to these message tokens.""" + import typing as ty import numpy as np -"""Defines message tokens for Actions (Commands) and Responses. Also defines -helper functions to convert scalar values to these message tokens""" - def enum_to_np(value: ty.Union[int, float], d_type: type = np.float64) -> np.array: diff --git a/src/lava/magma/runtime/runtime.py b/src/lava/magma/runtime/runtime.py index 95e007704..4c31bd093 100644 --- a/src/lava/magma/runtime/runtime.py +++ b/src/lava/magma/runtime/runtime.py @@ -7,7 +7,6 @@ import logging import sys import traceback -import typing import typing as ty import numpy as np from lava.magma.runtime.message_infrastructure import (RecvPort, @@ -19,6 +18,7 @@ getTempRecvPort, AbstractTransferPort) +from scipy.sparse import csr_matrix from lava.magma.compiler.var_model import AbstractVarModel, LoihiSynapseVarModel from lava.magma.runtime.message_infrastructure.message_interface_enum import \ ActorType @@ -119,7 +119,7 @@ def __init__(self, loglevel: int = logging.WARNING): self.log = logging.getLogger(__name__) self.log.setLevel(loglevel) - self._run_cond: typing.Optional[AbstractRunCondition] = None + self._run_cond: ty.Optional[AbstractRunCondition] = None self._executable: Executable = exe self._messaging_infrastructure_type: ActorType = \ @@ -134,6 +134,7 @@ def __init__(self, self.runtime_to_service: ty.Iterable[SendPort] = [] self.service_to_runtime: ty.Iterable[RecvPort] = [] self._open_ports: ty.List[AbstractTransferPort] = [] + self.num_steps: int = 0 def __del__(self): """On destruction, terminate Runtime automatically to @@ -523,6 +524,8 @@ def get_var(self, var_id: int, idx: np.ndarray = None) -> np.ndarray: req_port.send(np.array([addr_path])) buffer = recv_port.recv() recv_port.join() + if ev.dtype == csr_matrix: + return buffer[idx] if idx else buffer if buffer.dtype.type != np.str_: reshape_order = 'F' \ if isinstance(ev, LoihiSynapseVarModel) else 'C' @@ -531,6 +534,11 @@ def get_var(self, var_id: int, idx: np.ndarray = None) -> np.ndarray: # 2. Receive Data [NUM_ITEMS, DATA1, DATA2, ...] data_port: RecvPort = self.service_to_runtime[runtime_srv_id] num_items: int = int(data_port.recv()[0].item()) + if ev.dtype == csr_matrix: + buffer = np.zeros(num_items) + for i in range(num_items): + buffer[i] = data_port.recv()[0] + return buffer[idx] if idx else buffer buffer: np.ndarray = np.zeros((1, np.prod(ev.shape))) for i in range(num_items): buffer[0, i] = data_port.recv()[0] diff --git a/src/lava/magma/runtime/runtime_services/channel_broker/channel_broker.py b/src/lava/magma/runtime/runtime_services/channel_broker/channel_broker.py index 05e8f59ce..0a439a5b7 100644 --- a/src/lava/magma/runtime/runtime_services/channel_broker/channel_broker.py +++ b/src/lava/magma/runtime/runtime_services/channel_broker/channel_broker.py @@ -22,7 +22,6 @@ try: from nxcore.arch.base.nxboard import NxBoard from nxcore.graph.channel import Channel - from nxcore.graph.processes.phase_enums import Phase from nxcore.graph.processes.embedded.embedded_snip import EmbeddedSnip except ImportError: class NxBoard: diff --git a/src/lava/magma/runtime/runtime_services/runtime_service.py b/src/lava/magma/runtime/runtime_services/runtime_service.py index fcbcd8ba1..481abf6ed 100644 --- a/src/lava/magma/runtime/runtime_services/runtime_service.py +++ b/src/lava/magma/runtime/runtime_services/runtime_service.py @@ -2,6 +2,28 @@ # SPDX-License-Identifier: LGPL 2.1 or later # See: https://spdx.org/licenses/ +"""The RuntimeService interface is responsible for +coordinating the execution of a group of process models belonging to a common +synchronization domain. The domain will follow a SyncProtocol or will be +asynchronous. The processes and their corresponding process models are +selected by the Runtime dependent on the RunConfiguration assigned at the +start of execution. For each group of processes which follow the same +protocol and execute on the same node, the Runtime creates a RuntimeService. +Each RuntimeService coordinates all actions and commands from the Runtime, +transmitting them to the processes under its management and +returning action and command responses back to Runtime. + +RuntimeService Types: + +PyRuntimeService: (Abstract Class) Coordinates process models executing on + the CPU and written in Python. + Concrete Implementations: + a. LoihiPyRuntimeService: Coordinates process models executing on + the CPU and written in Python and following the LoihiProtocol. + b. AsyncPyRuntimeService: Coordinates process models executing on + the CPU and written in Python and following the AsyncProtocol. +""" + import logging import typing as ty from abc import abstractmethod @@ -27,28 +49,6 @@ from lava.magma.runtime.runtime_services.interfaces import \ AbstractRuntimeService -"""The RuntimeService interface is responsible for -coordinating the execution of a group of process models belonging to a common -synchronization domain. The domain will follow a SyncProtocol or will be -asynchronous. The processes and their corresponding process models are -selected by the Runtime dependent on the RunConfiguration assigned at the -start of execution. For each group of processes which follow the same -protocol and execute on the same node, the Runtime creates a RuntimeService. -Each RuntimeService coordinates all actions and commands from the Runtime, - transmitting them to the the processes under it's managment and -returning action and command responses back to Runtime. - -RuntimeService Types: - -PyRuntimeService: (Abstract Class) Coordinates process models executing on - the CPU and written in Python. - Concrete Implementations: - a. LoihiPyRuntimeService: Coordinates process models executing on - the CPU and written in Python and following the LoihiProtocol. - b. AsyncPyRuntimeService: Coordinates process models executing on - the CPU and written in Python and following the AsyncProtocol. -""" - class PyRuntimeService(AbstractRuntimeService): """Abstract RuntimeService for Python, it provides base methods @@ -80,7 +80,6 @@ def run(self): """Override this method to implement the runtime service. The run method is invoked upon start which called when the execution is started by the runtime.""" - pass def join(self): """Stop the necessary channels to coordinate with runtime and group @@ -106,7 +105,7 @@ def _relay_to_runtime_data_given_model_id(self, model_id: int): data_relay_port = self.service_to_runtime num_items = data_recv_port.recv() data_relay_port.send(num_items) - for i in range(int(num_items[0])): + for _ in range(int(num_items[0])): value = data_recv_port.recv() data_relay_port.send(value) @@ -128,7 +127,7 @@ def _relay_to_pm_data_given_model_id(self, model_id: int) -> MGMT_RESPONSE: num_items = data_recv_port.recv() data_relay_port.send(num_items) # Receive and relay data1, data2, ... - for i in range(int(num_items[0].item())): + for _ in range(int(num_items[0].item())): data_relay_port.send(data_recv_port.recv()) rsp = resp_port.recv() return rsp @@ -212,12 +211,12 @@ def _next_phase(self, is_last_time_step: bool): if self.req_pre_lrn_mgmt: self.req_pre_lrn_mgmt = False return LoihiPyRuntimeService.Phase.PRE_MGMT - if self.req_post_lrn_mgmt: - self.req_post_lrn_mgmt = False - return LoihiPyRuntimeService.Phase.POST_MGMT if self.req_lrn: self.req_lrn = False return LoihiPyRuntimeService.Phase.LRN + if self.req_post_lrn_mgmt: + self.req_post_lrn_mgmt = False + return LoihiPyRuntimeService.Phase.POST_MGMT if self.req_pause: self.req_pause = False return MGMT_COMMAND.PAUSE diff --git a/src/lava/proc/conv/utils.py b/src/lava/proc/conv/utils.py index c47e9c5b6..73572af8f 100644 --- a/src/lava/proc/conv/utils.py +++ b/src/lava/proc/conv/utils.py @@ -157,7 +157,7 @@ def output_shape(input_shape: Tuple[int, int, int], return x_out, y_out, out_channels -def conv(input: np.ndarray, +def conv(input_: np.ndarray, weight: np.ndarray, kernel_size: Tuple[int, int], stride: Tuple[int, int], @@ -168,7 +168,7 @@ def conv(input: np.ndarray, Parameters ---------- - input : 3 dimensional np array + input_ : 3 dimensional np array convolution input. weight : 4 dimensional np array convolution kernel weight. @@ -192,7 +192,7 @@ def conv(input: np.ndarray, # with torch.no_grad(): # this seems to cause problems output = F.conv2d( torch.unsqueeze( # torch expects a batch dimension NCHW - torch.FloatTensor(input.transpose([2, 1, 0])), + torch.FloatTensor(input_.transpose([2, 1, 0])), dim=0, ), torch.FloatTensor( @@ -209,13 +209,13 @@ def conv(input: np.ndarray, )[0].cpu().data.numpy().transpose([2, 1, 0]) else: output = conv_scipy( - input, weight, kernel_size, stride, padding, dilation, groups + input_, weight, kernel_size, stride, padding, dilation, groups ) return output.astype(weight.dtype) -def conv_scipy(input: np.ndarray, +def conv_scipy(input_: np.ndarray, weight: np.ndarray, kernel_size: Tuple[int, int], stride: Tuple[int, int], @@ -226,7 +226,7 @@ def conv_scipy(input: np.ndarray, Parameters ---------- - input : 3 dimensional np array + input_ : 3 dimensional np array convolution input. weight : 4 dimensional np array convolution kernel weight. @@ -246,7 +246,7 @@ def conv_scipy(input: np.ndarray, 3 dimensional np array convolution output """ - input_shape = input.shape + input_shape = input_.shape output = np.zeros( output_shape( input_shape, weight.shape[0], @@ -263,12 +263,12 @@ def conv_scipy(input: np.ndarray, dilated_weight[:, ::dilation[0], ::dilation[1], :] = weight input_padded = np.pad( - input, + input_, ((padding[0], padding[0]), (padding[1], padding[1]), (0, 0)), mode='constant', ) - if input.shape[-1] % groups != 0: + if input_.shape[-1] % groups != 0: raise Exception( f'Expected number of in_channels to be divisible by group.' f'Found {weight.shape[3] = } and {groups = }.' @@ -280,7 +280,7 @@ def conv_scipy(input: np.ndarray, ) k_grp = output.shape[2] // groups - c_grp = input.shape[2] // groups + c_grp = input_.shape[2] // groups for g in range(groups): for k in range(k_grp): for c in range(c_grp): diff --git a/src/lava/proc/dense/models.py b/src/lava/proc/dense/models.py index b14588b2c..1761110dd 100644 --- a/src/lava/proc/dense/models.py +++ b/src/lava/proc/dense/models.py @@ -72,9 +72,10 @@ def __init__(self, proc_params): super().__init__(proc_params) # Flag to determine whether weights have already been scaled. self.weights_set = False + self.weight_exp: int = self.proc_params.get("weight_exp", 0) def run_spk(self): - self.weight_exp: int = self.proc_params.get("weight_exp", 0) + self.weight_exp = self.proc_params.get("weight_exp", 0) # Since this Process has no learning, weights are assumed to be static # and only require scaling on the first timestep of run_spk(). @@ -148,9 +149,9 @@ def run_spk(self): @tag("bit_approximate_loihi", "fixed_pt") class PyLearningDenseModelBitApproximate( LearningConnectionModelBitApproximate, AbstractPyDenseModelBitAcc): - """Implementation of Conn Process with Dense synaptic connections that is - bit-accurate with Loihi's hardware implementation of Dense, which means, - it mimics Loihi behaviour bit-by-bit. + """Implementation of Conn Process with Dense synaptic connections that + uses similar constraints as Loihi's hardware implementation of dense + connectivity but does not reproduce Loihi bit-by-bit. """ def __init__(self, proc_params): @@ -347,14 +348,38 @@ class AbstractPyDelayDenseModel(PyLoihiProcessModel): """Abstract Conn Process with Dense synaptic connections which incorporates delays into the Conn Process. """ + weights: np.ndarray = None + delays: np.ndarray = None + a_buff: np.ndarray = None + + def calc_act(self, s_in) -> np.ndarray: + """ + Calculate the activation matrix based on s_in by performing + delay_wgts * s_in. + """ + # First calculating the activations through delay_wgts * s_in + # This matrix is then summed across each row to get the + # activations to the output neurons for different delays. + # This activation vector is reshaped to a matrix of the form + # (n_flat_output_neurons * (max_delay + 1), n_flat_output_neurons) + # which is then transposed to get the activation matrix. + return np.reshape( + np.sum(self.get_delay_wgts_mat(self.weights, + self.delays) * s_in, axis=1), + (np.max(self.delays) + 1, self.weights.shape[0])).T @staticmethod - def get_del_wgts(weights, delays) -> np.ndarray: + def get_delay_wgts_mat(weights, delays) -> np.ndarray: """ - Use self.weights and self.delays to create a matrix where the - weights are separated by delay. Returns 2D matrix of form + Create a matrix where the synaptic weights are separated + by their corresponding delays. The first matrix contains all the + weights, where the delay is equal to zero. The second matrix + contains all the weights, where the delay is equal to one and so on. + These matrices are then stacked together vertically. + + Returns 2D matrix of form (num_flat_output_neurons * max_delay + 1, num_flat_input_neurons) where - del_wgts[ + delay_wgts[ k * num_flat_output_neurons : (k + 1) * num_flat_output_neurons, : ] contains the weights for all connections with a delay equal to k. @@ -366,20 +391,6 @@ def get_del_wgts(weights, delays) -> np.ndarray: for k in range(np.max(delays) + 1) ]) - def calc_act(self, s_in) -> np.ndarray: - """ - Calculate the activations by performing del_wgts * s_in. This matrix - is then summed across each row to get the activations to the output - neurons for different delays. This activation vector is reshaped to a - matrix of the form - (n_flat_output_neurons * (max_delay + 1), n_flat_output_neurons) - which is then transposed to get the activation matrix. - """ - return np.reshape( - np.sum(self.get_del_wgts(self.weights, - self.delays) * s_in, axis=1), - (np.max(self.delays) + 1, self.weights.shape[0])).T - def update_act(self, s_in): """ Updates the activations for the connection. @@ -416,7 +427,7 @@ class PyDelayDenseModelFloat(AbstractPyDelayDenseModel): num_message_bits: np.ndarray = LavaPyType(np.ndarray, int, precision=5) def run_spk(self): - # The a_out sent on a each timestep is a buffered value from dendritic + # The a_out sent on 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]) diff --git a/src/lava/proc/dense/process.py b/src/lava/proc/dense/process.py index 89d58c3ba..c2c0baf7e 100644 --- a/src/lava/proc/dense/process.py +++ b/src/lava/proc/dense/process.py @@ -232,17 +232,18 @@ def __init__(self, spikes as binary spikes (num_message_bits = 0) or as graded spikes (num_message_bits > 0). Default is 0. """ + if max_delay == 0: + max_delay = int(np.max(delays)) super().__init__(weights=weights, num_message_bits=num_message_bits, name=name, log_config=log_config, + max_delay=max_delay, **kwargs) self._validate_delays(weights, delays) shape = weights.shape - if max_delay == 0: - max_delay = int(np.max(delays)) # Variables self.delays = Var(shape=shape, init=delays) diff --git a/src/lava/proc/io/encoder.py b/src/lava/proc/io/encoder.py index 6a2fe39e7..3e284ce85 100644 --- a/src/lava/proc/io/encoder.py +++ b/src/lava/proc/io/encoder.py @@ -15,7 +15,6 @@ from lava.magma.core.resources import HostCPU from lava.magma.core.decorator import implements, requires, tag from lava.magma.core.model.py.model import PyLoihiProcessModel -from lava.proc.sdn.models import AbstractDeltaModel @unique diff --git a/src/lava/proc/lif/models.py b/src/lava/proc/lif/models.py index 1d7bd3a75..b58ffe7db 100644 --- a/src/lava/proc/lif/models.py +++ b/src/lava/proc/lif/models.py @@ -1,7 +1,11 @@ -# Copyright (C) 2021-22 Intel Corporation +# Copyright (C) 2021-23 Intel Corporation # SPDX-License-Identifier: BSD-3-Clause # See: https://spdx.org/licenses/ +from lava.magma.core.model.py.neuron import ( + LearningNeuronModelFloat, + LearningNeuronModelFixed, +) import numpy as np from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol from lava.magma.core.model.py.ports import PyInPort, PyOutPort @@ -9,12 +13,8 @@ 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.lif.process import LIF, LIFReset, TernaryLIF, LearningLIF - -from lava.magma.core.model.py.neuron import ( - LearningNeuronModelFloat, - LearningNeuronModelFixed, -) +from lava.proc.lif.process import (LIF, LIFReset, TernaryLIF, LearningLIF, + LIFRefractory) class AbstractPyLifModelFloat(PyLoihiProcessModel): @@ -449,6 +449,60 @@ def run_spk(self): self.s_out.send(s_out) +@implements(proc=LIFRefractory, protocol=LoihiProtocol) +@requires(CPU) +@tag("floating_pt") +class PyLifRefractoryModelFloat(AbstractPyLifModelFloat): + """Implementation of Leaky-Integrate-and-Fire neural process with + refractory period in floating point precision. + """ + + s_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, float) + vth: float = LavaPyType(float, float) + refractory_period_end: np.ndarray = LavaPyType(np.ndarray, int) + + def __init__(self, proc_params): + super(PyLifRefractoryModelFloat, self).__init__(proc_params) + self.refractory_period = proc_params["refractory_period"] + + def spiking_activation(self): + """Spiking activation function for LIF Refractory.""" + return self.v > self.vth + + def subthr_dynamics(self, activation_in: np.ndarray): + """Sub-threshold dynamics of current and voltage variables for + all refractory LIF models. This is where the 'leaky integration' + happens. + """ + 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]) + + def process_spikes(self, spike_vector: np.ndarray): + self.refractory_period_end[spike_vector] = (self.time_step + + self.refractory_period) + super().reset_voltage(spike_vector) + + def run_spk(self): + """The run function that performs the actual computation during + execution orchestrated by a PyLoihiProcessModel using the + LoihiProtocol. + """ + # Receive synaptic input + a_in_data = self.a_in.recv() + + self.subthr_dynamics(activation_in=a_in_data) + + s_out = self.spiking_activation() + + # Reset voltage of spiked neurons to 0 + self.process_spikes(spike_vector=s_out) + self.s_out.send(s_out) + + @implements(proc=LearningLIF, protocol=LoihiProtocol) @requires(CPU) @tag("bit_accurate_loihi", "fixed_pt") diff --git a/src/lava/proc/lif/process.py b/src/lava/proc/lif/process.py index 426f9b216..d658755b8 100644 --- a/src/lava/proc/lif/process.py +++ b/src/lava/proc/lif/process.py @@ -1,14 +1,11 @@ -# Copyright (C) 2022 Intel Corporation +# 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.magma.core.learning.learning_rule import ( - LoihiLearningRule, - Loihi2FLearningRule, -) +from lava.magma.core.learning.learning_rule import Loihi2FLearningRule from lava.magma.core.process.process import LogConfig, AbstractProcess from lava.magma.core.process.variable import Var from lava.magma.core.process.ports.ports import InPort, OutPort @@ -347,3 +344,75 @@ def __init__( self.proc_params["reset_interval"] = reset_interval self.proc_params["reset_offset"] = reset_offset + + +class LIFRefractory(LIF): + + """Leaky-Integrate-and-Fire (LIF) process with refractory period. + + Parameters + ---------- + shape : tuple(int) + Number and topology of LIF neurons. + u : float, list, numpy.ndarray, optional + Initial value of the neurons' current. + v : float, list, numpy.ndarray, optional + Initial value of the neurons' voltage (membrane potential). + du : float, optional + Inverse of decay time-constant for current decay. Currently, only a + single decay can be set for the entire population of neurons. + dv : float, optional + Inverse of decay time-constant for voltage decay. Currently, only a + single decay can be set for the entire population of neurons. + bias_mant : float, list, numpy.ndarray, optional + Mantissa part of neuron bias. + bias_exp : float, list, numpy.ndarray, optional + Exponent part of neuron bias, if needed. Mostly for fixed point + implementations. Ignored for floating point implementations. + vth : float, optional + Neuron threshold voltage, exceeding which, the neuron will spike. + Currently, only a single threshold can be set for the entire + population of neurons. + refractory_period : int, optional + The interval of the refractory period. 1 timestep by default. + + + See Also + -------- + lava.proc.lif.process.LIF: 'Regular' leaky-integrate-and-fire neuron for + documentation on rest of the behavior. + """ + + def __init__( + self, + *, + shape: ty.Tuple[int, ...], + u: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + v: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + du: ty.Optional[float] = 0, + dv: ty.Optional[float] = 0, + bias_mant: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + bias_exp: ty.Optional[ty.Union[float, list, np.ndarray]] = 0, + vth: ty.Optional[float] = 10, + refractory_period: ty.Optional[int] = 1, + name: ty.Optional[str] = None, + log_config: ty.Optional[LogConfig] = None, + ) -> None: + super().__init__( + shape=shape, + u=u, + v=v, + du=du, + dv=dv, + bias_mant=bias_mant, + bias_exp=bias_exp, + vth=vth, + name=name, + log_config=log_config, + ) + + if refractory_period < 1: + raise ValueError("Refractory period must be > 0.") + + self.proc_params["refractory_period"] = refractory_period + self.refractory_period_end = Var(shape=shape, init=0) diff --git a/src/lava/proc/monitor/process.py b/src/lava/proc/monitor/process.py index b907c4103..0c8b4d17a 100644 --- a/src/lava/proc/monitor/process.py +++ b/src/lava/proc/monitor/process.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: BSD-3-Clause # See: https://spdx.org/licenses/ -import matplotlib.pyplot as plt 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, RefPort @@ -131,23 +130,19 @@ def probe(self, target, num_steps): # Create names for Ports/Vars to be created in Monitor process for # probing purposes. Names are given incrementally each time probe(..) # method is called. - self.new_ref_port_name = "ref_port_" + \ - str(self.proc_params["n_ref_ports"]) - self.new_var_read_name = "var_read_" + \ - str(self.proc_params["n_ref_ports"]) - self.new_in_port_name = "in_port_" + \ - str(self.proc_params["n_in_ports"]) - self.new_out_read_name = "out_read_" + \ - str(self.proc_params["n_in_ports"]) + new_ref_port_name = f"ref_port_{self.proc_params['n_ref_ports']}" + new_var_read_name = f"var_read_{self.proc_params['n_ref_ports']}" + new_in_port_name = f"in_port_{self.proc_params['n_in_ports']}" + new_out_read_name = f"out_read_{self.proc_params['n_in_ports']}" # Create and set new Refport and corresponding Var to store data - setattr(self, self.new_ref_port_name, RefPort(shape=target.shape)) - setattr(self, self.new_var_read_name, + setattr(self, new_ref_port_name, RefPort(shape=target.shape)) + setattr(self, new_var_read_name, Var(shape=(num_steps,) + target.shape, init=0)) # Create and set new InPort and corresponding Var to store data - setattr(self, self.new_in_port_name, InPort(shape=target.shape)) - setattr(self, self.new_out_read_name, + setattr(self, new_in_port_name, InPort(shape=target.shape)) + setattr(self, new_out_read_name, Var(shape=(num_steps,) + target.shape, init=0)) # Add the names of new RefPort and Var_read name to proc_params dict @@ -179,11 +174,11 @@ def probe(self, target, num_steps): self.proc_params.overwrite("n_ref_ports", n_ref_ports + 1) # Connect newly created Refport to the var to be monitored - getattr(self, self.new_ref_port_name).connect_var(target) + getattr(self, new_ref_port_name).connect_var(target) # Add the name of probed Var and its process to the target_names - self.target_names[self.new_var_read_name] = [target.process.name, - target.name] + self.target_names[new_var_read_name] = [target.process.name, + target.name] # If target to be monitored is an OutPort elif isinstance(target, OutPort): @@ -192,11 +187,11 @@ def probe(self, target, num_steps): self.proc_params.overwrite("n_in_ports", n_in_ports + 1) # Connect newly created InPort from the OutPort to be monitored - getattr(self, self.new_in_port_name).connect_from(target) + getattr(self, new_in_port_name).connect_from(target) # Add the name of OutPort and its process to the target_names - self.target_names[self.new_out_read_name] = [target.process.name, - target.name] + self.target_names[new_out_read_name] = [target.process.name, + target.name] # If target is an InPort raise a Type error, as monitoring InPorts is # not supported yet diff --git a/src/lava/proc/sparse/models.py b/src/lava/proc/sparse/models.py new file mode 100644 index 000000000..cd7b4abc3 --- /dev/null +++ b/src/lava/proc/sparse/models.py @@ -0,0 +1,372 @@ +# Copyright (C) 2023 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +from scipy.sparse import csr_matrix, spmatrix, vstack, find +from lava.magma.core.model.py.connection import ( + LearningConnectionModelFloat, + LearningConnectionModelBitApproximate, +) +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.sparse.process import Sparse, DelaySparse, LearningSparse +from lava.utils.weightutils import SignMode, determine_sign_mode,\ + truncate_weights, clip_weights + + +class AbstractPySparseModelFloat(PyLoihiProcessModel): + """Implementation of Conn Process with Sparse 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. + """ + + 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) + # weights is a 2D matrix of form (num_flat_output_neurons, + # num_flat_input_neurons) in C-order (row major). + weights: csr_matrix = LavaPyType(csr_matrix, float) + num_message_bits: np.ndarray = LavaPyType(np.ndarray, int, precision=5) + + def run_spk(self): + # The a_out sent on 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) + if self.num_message_bits.item() > 0: + s_in = self.s_in.recv() + self.a_buff = self.weights.dot(s_in) + else: + s_in = self.s_in.recv().astype(bool) + # A1: return as flattend array + self.a_buff = self.weights[:, s_in].sum(axis=1).A1 + + +@implements(proc=Sparse, protocol=LoihiProtocol) +@requires(CPU) +@tag("floating_pt") +class PySparseModelFloat(AbstractPySparseModelFloat): + pass + + +class AbstractPySparseModelBitAcc(PyLoihiProcessModel): + """Implementation of Conn Process with Sparse synaptic connections that is + bit-accurate with Loihi's hardware implementation of Sparse, which means, + it reproduces Loihi behavior bit-by-bit. + """ + + s_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, bool, precision=1) + a_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, np.int32, precision=16) + a_buff: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=16) + # weights is a 2D matrix of form (num_flat_output_neurons, + # num_flat_input_neurons) in C-order (row major). + weights: np.ndarray = LavaPyType(csr_matrix, np.int32, precision=8) + num_message_bits: np.ndarray = LavaPyType(np.ndarray, int, precision=5) + + def __init__(self, proc_params): + super().__init__(proc_params) + # Flag to determine whether weights have already been scaled. + self.weights_set = False + + def run_spk(self): + # pylint: disable=W0201 + self.weight_exp: int = self.proc_params.get("weight_exp", 0) + + # Since this Process has no learning, weights are assumed to be static + # and only require scaling on the first timestep of run_spk(). + if not self.weights_set: + num_weight_bits: int = self.proc_params.get("num_weight_bits", 8) + sign_mode: SignMode = self.proc_params.get("sign_mode") \ + or determine_sign_mode(self.weights) + + self.weights = clip_weights(self.weights, sign_mode, num_bits=8) + self.weights = truncate_weights(self.weights, + sign_mode, + num_weight_bits) + self.weights_set = True + + # The a_out sent at 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) + if self.num_message_bits.item() > 0: + s_in = self.s_in.recv() + a_accum = self.weights.dot(s_in) + else: + s_in = self.s_in.recv().astype(bool) + a_accum = self.weights[:, s_in].sum(axis=1).A1 + self.a_buff = ( + np.left_shift(a_accum, self.weight_exp) + if self.weight_exp > 0 + else np.right_shift(a_accum, -self.weight_exp) + ) + + +@implements(proc=Sparse, protocol=LoihiProtocol) +@requires(CPU) +@tag("bit_accurate_loihi", "fixed_pt") +class PySparseModelBitAcc(AbstractPySparseModelBitAcc): + pass + + +@implements(proc=LearningSparse, protocol=LoihiProtocol) +@requires(CPU) +@tag("floating_pt") +class PyLearningSparseModelFloat( + LearningConnectionModelFloat, AbstractPySparseModelFloat): + """Implementation of Conn Process with Sparse 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. + + Warning: LearningSparse on CPU is not offering any memory usage benefits + over using LearningDense. + """ + + # Overwrite dense PyTypes with sparse + tag_1: csr_matrix = LavaPyType(csr_matrix, float) + tag_2: csr_matrix = LavaPyType(csr_matrix, float) + + def __init__(self, proc_params): + super().__init__(proc_params) + + def run_spk(self): + # The a_out sent at 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) + if self.num_message_bits.item() > 0: + s_in = self.s_in.recv() + self.a_buff = self.weights.dot(s_in) + else: + s_in = self.s_in.recv().astype(bool) + self.a_buff = self.weights[:, s_in].sum(axis=1).A1 + + self.recv_traces(s_in) + + +@implements(proc=LearningSparse, protocol=LoihiProtocol) +@requires(CPU) +@tag("bit_approximate_loihi", "fixed_pt") +class PyLearningSparseModelBitApproximate( + LearningConnectionModelBitApproximate, AbstractPySparseModelBitAcc): + """Implementation of Conn Process with Sparse synaptic connections that + uses similar constraints as Loihi's hardware implementation of sparse + connectivity but does not reproduce Loihi bit-by-bit. + + Warning: LearningSparse on CPU is not offering any memory usage benefits + over using LearningDense. + """ + # Overwrite dense PyTypes with sparse + tag_1: csr_matrix = LavaPyType(csr_matrix, int, precision=8) + tag_2: csr_matrix = LavaPyType(csr_matrix, int, precision=6) + + def __init__(self, proc_params): + super().__init__(proc_params) + # Flag to determine whether weights have already been scaled. + self.num_weight_bits: int = self.proc_params.get("num_weight_bits", 8) + + def run_spk(self): + self.weight_exp: int = self.proc_params.get("weight_exp", 0) + + # Since this Process has no learning, weights are assumed to be static + # and only require scaling on the first timestep of run_spk(). + if not self.weights_set: + self.weights = truncate_weights( + self.weights, + sign_mode=self.sign_mode, + num_weight_bits=self.num_weight_bits + ) + self.weights_set = True + + # The a_out sent at 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) + if self.num_message_bits.item() > 0: + s_in = self.s_in.recv() + a_accum = self.weights.dot(s_in) + else: + s_in = self.s_in.recv().astype(bool) + a_accum = self.weights[:, s_in].sum(axis=1).A1 + + self.a_buff = ( + np.left_shift(a_accum, self.weight_exp) + if self.weight_exp > 0 + else np.right_shift(a_accum, -self.weight_exp) + ) + + self.recv_traces(s_in) + + +class AbstractPyDelaySparseModel(PyLoihiProcessModel): + """Abstract Conn Process with Sparse synaptic connections which incorporates + delays into the Conn Process. + """ + weights: csr_matrix = None + delays: csr_matrix = None + a_buff: np.ndarray = None + + def calc_act(self, s_in) -> np.ndarray: + """ + Calculate the activation matrix based on s_in by performing + delay_wgts * s_in. + """ + # First calculating the activations through delay_wgts * s_in + # This matrix is then summed across each row to get the + # activations to the output neurons for different delays. + # This activation vector is reshaped to a matrix of the form + # (n_flat_output_neurons * (max_delay + 1), n_flat_output_neurons) + # which is then transposed to get the activation matrix. + return np.reshape(self.get_delay_wgts_mat(self.weights, + self.delays).dot(s_in), + (np.max(self.delays) + 1, + self.weights.shape[0])).T + + @staticmethod + def get_delay_wgts_mat(weights, delays) -> spmatrix: + """ + Create a matrix where the synaptic weights are separated + by their corresponding delays. The first matrix contains all the + weights, where the delay is equal to zero. The second matrix + contains all the weights, where the delay is equal to one and so on. + These matrices are then stacked together vertically. + + Returns 2D matrix of form + (num_flat_output_neurons * max_delay + 1, num_flat_input_neurons) where + delay_wgts[ + k * num_flat_output_neurons : (k + 1) * num_flat_output_neurons, : + ] + contains the weights for all connections with a delay equal to k. + This allows for the updating of the activation buffer and updating + weights. + """ + # Can only start at 1, as delays==0 raises inefficiency warning + if np.max(delays) == 0: + return weights + + weight_delay_from_1 = vstack([weights.multiply(delays == k) + for k in range(1, np.max(delays) + 1)]) + # Create weight matrix at delays == 0 + r, c, _ = find(delays) + weight_delay_zeros = weights.copy() + weight_delay_zeros[r, c] = 0 + weight_delay_zeros.eliminate_zeros() + return vstack([weight_delay_zeros, weight_delay_from_1]) + + 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.a_buff += self.calc_act(s_in) + + +@implements(proc=DelaySparse, protocol=LoihiProtocol) +@requires(CPU) +@tag("floating_pt") +class PyDelaySparseModelFloat(AbstractPyDelaySparseModel): + """Implementation of Conn Process with Sparse 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. DelaySparse 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) + # weights is a 2D matrix of form (num_flat_output_neurons, + # num_flat_input_neurons) in C-order (row major). + weights: np.ndarray = LavaPyType(csr_matrix, float) + # delays is a 2D matrix of form (num_flat_output_neurons, + # num_flat_input_neurons) in C-order (row major). + delays: np.ndarray = LavaPyType(csr_matrix, int) + num_message_bits: np.ndarray = LavaPyType(np.ndarray, int, precision=5) + + def run_spk(self): + # The a_out sent on 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=DelaySparse, protocol=LoihiProtocol) +@requires(CPU) +@tag("bit_accurate_loihi", "fixed_pt") +class PyDelaySparseModelBitAcc(AbstractPyDelaySparseModel): + """Implementation of Conn Process with Sparse synaptic connections that is + bit-accurate with Loihi's hardware implementation of Sparse, which means, + it mimics Loihi behaviour bit-by-bit. DelaySparse incorporates delays into + the Conn Process. Loihi 2 has a maximum of 6 bits for delays, meaning a + spike can be delayed by 0 to 63 time steps.""" + + s_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, bool, precision=1) + a_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, np.int32, precision=16) + a_buff: np.ndarray = LavaPyType(np.ndarray, np.int32, precision=16) + # weights is a 2D matrix of form (num_flat_output_neurons, + # num_flat_input_neurons) in C-order (row major). + weights: csr_matrix = LavaPyType(csr_matrix, np.int32, precision=8) + delays: csr_matrix = LavaPyType(csr_matrix, np.int32, precision=6) + num_message_bits: np.ndarray = LavaPyType(np.ndarray, int, precision=5) + + def __init__(self, proc_params): + super().__init__(proc_params) + # Flag to determine whether weights have already been scaled. + self.weights_set = False + + def run_spk(self): + self.weight_exp: int = self.proc_params.get("weight_exp", 0) + + # Since this Process has no learning, weights are assumed to be static + # and only require scaling on the first timestep of run_spk(). + if not self.weights_set: + num_weight_bits: int = self.proc_params.get("num_weight_bits", 8) + sign_mode: SignMode = self.proc_params.get("sign_mode") \ + or determine_sign_mode(self.weights) + + self.weights = clip_weights(self.weights, sign_mode, num_bits=8) + self.weights = truncate_weights(self.weights, + sign_mode, + num_weight_bits) + self.weights_set = True + + # Check if delays are within Loihi 2 constraints + if np.max(self.delays) > 63: + raise ValueError("DelaySparse Process 'delays' expects values " + f"between 0 and 63 for Loihi, got " + f"{self.delays}.") + + # The a_out sent at 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) + + a_accum = self.calc_act(s_in) + self.a_buff[:, 0] = 0 + self.a_buff = np.roll(self.a_buff, -1) + self.a_buff += ( + np.left_shift(a_accum, self.weight_exp) + if self.weight_exp > 0 + else np.right_shift(a_accum, -self.weight_exp) + ) diff --git a/src/lava/proc/sparse/process.py b/src/lava/proc/sparse/process.py new file mode 100644 index 000000000..d8c52c7ce --- /dev/null +++ b/src/lava/proc/sparse/process.py @@ -0,0 +1,277 @@ +# Copyright (C) 2021-23 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import numpy as np +from scipy.sparse import spmatrix +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 +from lava.magma.core.process.connection import LearningConnectionProcess +from lava.magma.core.learning.constants import GradedSpikeCfg +from lava.magma.core.learning.learning_rule import LoihiLearningRule + + +class Sparse(AbstractProcess): + """Sparse connections between neurons. Realizes the following abstract + behavior: a_out = weights * s_in. The weights are stored as + scipy.sparse.csr_matrix. + + Parameters + ---------- + weights : scipy.sparse.spmatrix + 2D connection weight matrix as sparse matrix of form + (num_flat_output_neurons, num_flat_input_neurons). + + 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 Sparse 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: spmatrix, + name: ty.Optional[str] = None, + num_message_bits: ty.Optional[int] = 0, + log_config: ty.Optional[LogConfig] = None, + **kwargs) -> None: + + super().__init__(num_message_bits=num_message_bits, + name=name, + log_config=log_config, + **kwargs) + + # Transform weights to csr matrix + weights = weights.tocsr() + + shape = weights.shape + + # Ports + self.s_in = InPort(shape=(shape[1],)) + self.a_out = OutPort(shape=(shape[0],)) + + # 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) + + +class LearningSparse(LearningConnectionProcess, Sparse): + """Sparse connections between neurons. Realizes the following abstract + behavior: a_out = weights * s_in. The weights are stored as + scipy.sparse.csr_matrix. + + Parameters + ---------- + weights : scipy.sparse.spmatrix + 2D connection weight matrix as sparse matrix of form + (num_flat_output_neurons, num_flat_input_neurons). + + 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 Sparse Process deals with the incoming + spikes as binary spikes (num_message_bits = 0) or as graded + spikes (num_message_bits > 0). Default is 0. + + learning_rule: LoihiLearningRule + Learning rule which determines the parameters for online learning. + + graded_spike_cfg: GradedSpikeCfg + Indicates how to use incoming graded spike to update pre-synaptic + traces. + + (0) GradedSpikeCfg.USE_REGULAR_IMPULSE interprets the spike as a + binary spike, adds regular impulses to pre-synaptic traces, at the end + of the epoch. + (1) GradedSpikeCfg.OVERWRITE interprets the spike as a graded spike, + overwrites the value of the pre-synaptic trace x1 by payload/2, + upon spiking. + (2) GradedSpikeCfg.ADD_WITH_SATURATION interprets the spike as a graded + spike, adds payload/2 to the pre-synaptic trace x1, upon spiking, + saturates x1 to 127 (fixed-pt/hw only). + (3) GradedSpikeCfg.ADD_WITHOUT_SATURATION interprets the spike as a + graded spike, adds payload/2 to the pre-synaptic trace x1, upon spiking, + keeps only overflow above 127 in x1 (fixed-pt/hw only), adds regular + impulse to x2 on overflow. + In addition, only pre-synaptic graded spikes that trigger overflow in + x1 and regular impulse addition to x2 will be considered by the + learning rule Products conditioned on x0. + """ + def __init__(self, + *, + weights: spmatrix, + name: ty.Optional[str] = None, + num_message_bits: ty.Optional[int] = 0, + log_config: ty.Optional[LogConfig] = None, + learning_rule: LoihiLearningRule = None, + graded_spike_cfg: GradedSpikeCfg = + GradedSpikeCfg.USE_REGULAR_IMPULSE, + **kwargs) -> None: + + if graded_spike_cfg != GradedSpikeCfg.USE_REGULAR_IMPULSE: + learning_rule.x1_impulse = 0 + + super().__init__(weights=weights, + shape=weights.shape, + num_message_bits=num_message_bits, + name=name, + log_config=log_config, + learning_rule=learning_rule, + graded_spike_cfg=graded_spike_cfg, + **kwargs) + + # Transform weights to csr matrix + weights = weights.tocsr() + + shape = weights.shape + + # Ports + self.s_in = InPort(shape=(shape[1],)) + self.a_out = OutPort(shape=(shape[0],)) + + # 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) + + +class DelaySparse(Sparse): + def __init__(self, + *, + weights: spmatrix, + delays: ty.Union[spmatrix, int], + max_delay: ty.Optional[int] = 0, + name: ty.Optional[str] = None, + num_message_bits: ty.Optional[int] = 0, + log_config: ty.Optional[LogConfig] = None, + **kwargs) -> None: + """Sparse, delayed connections between neurons. Realizes the following + abstract behavior: a_out = weights * s_in + + Parameters + ---------- + weights : spmatrix + 2D connection weight matrix of form (num_flat_output_neurons, + num_flat_input_neurons) in C-order (row major). + + delays : spmatrix, int + 2D connection delay matrix of form (num_flat_output_neurons, + num_flat_input_neurons) in C-order (row major) or integer value if + the same delay should be used for all synapses. + + max_delay: int, optional + Maximum expected delay. Should be set if delays change during + execution. Default value is 0, in this case the maximum delay + will be determined from the values given in 'delays'. + + 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 Sparse Process deals with the incoming + spikes as binary spikes (num_message_bits = 0) or as graded + spikes (num_message_bits > 0). Default is 0. + """ + if max_delay == 0: + max_delay = int(np.max(delays)) + + super().__init__(weights=weights, + num_message_bits=num_message_bits, + name=name, + log_config=log_config, + max_delay=max_delay, + **kwargs) + + self._validate_delays(weights, delays) + shape = weights.shape + + # Variables + self.delays = Var(shape=shape, init=delays) + self.a_buff = Var(shape=(shape[0], max_delay + 1), init=0) + + @staticmethod + def _validate_delays(weights: spmatrix, delays: spmatrix) -> None: + if np.min(delays) < 0: + raise ValueError("DelaySparse Process 'delays' expects only " + f"positive values, got {delays}.") + if not isinstance(delays, int): + if weights.shape != delays.shape: + raise ValueError("DelaySparse Process 'delays' expects same " + f"shape as the weight matrix or int, got " + f"{delays}.") + if delays.dtype != int: + raise ValueError("DelaySparse Process 'delays' expects integer " + f"value(s), got {delays}.") diff --git a/src/lava/proc/spiker/models.py b/src/lava/proc/spiker/models.py index 17352767f..af5b7d5d9 100644 --- a/src/lava/proc/spiker/models.py +++ b/src/lava/proc/spiker/models.py @@ -5,7 +5,7 @@ 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.ports import 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 diff --git a/src/lava/utils/dataloader/mnist.py b/src/lava/utils/dataloader/mnist.py index c7b9e4eaa..724b25a34 100644 --- a/src/lava/utils/dataloader/mnist.py +++ b/src/lava/utils/dataloader/mnist.py @@ -56,7 +56,8 @@ def download_mnist(path=os.path.join(os.path.dirname(__file__), 'temp')): f.write(res.read()) break else: - raise "Url does not start with http" + raise ValueError(f"Specified URL ({url}) does not " + "start with 'http'.") except urllib.error.URLError as exception: err = exception continue diff --git a/src/lava/utils/sparse.py b/src/lava/utils/sparse.py new file mode 100644 index 000000000..8abb8ab59 --- /dev/null +++ b/src/lava/utils/sparse.py @@ -0,0 +1,32 @@ +# Copyright (C) 2023 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import typing as ty + +from scipy.sparse import csr_matrix, find as scipy_find + + +def find(mat: csr_matrix, + explicit_zeros: bool = False) -> ty.Tuple: + """Behaves like scipy.sparse.find but also returns explict zeros. + + Parameters + ========== + mat: csr_matrix + Return col, row and values of this sparse matrix. + explicit_zeros: bool + Include explicit zeros + """ + if not explicit_zeros: + return scipy_find(mat) + + idx = mat.data == 0 + + mat.data[idx] = 1 + dst, src, _ = scipy_find(mat) + mat.data[idx] = 0 + + vals = mat[dst, src].A1 # A1 returns values in flattened array + + return dst, src, vals diff --git a/src/lava/utils/weightutils.py b/src/lava/utils/weightutils.py index 587bf9282..0230da93e 100644 --- a/src/lava/utils/weightutils.py +++ b/src/lava/utils/weightutils.py @@ -3,6 +3,7 @@ # See: https://spdx.org/licenses/ import numpy as np +from scipy.sparse import spmatrix import typing as ty from enum import Enum, unique from dataclasses import dataclass @@ -44,20 +45,20 @@ def determine_sign_mode(weights: np.ndarray) -> SignMode: @dataclass class OptimizedWeights: - weights: np.ndarray + weights: ty.Union[np.ndarray, spmatrix] num_weight_bits: int weight_exp: int def optimize_weight_bits( - weights: np.ndarray, + weights: ty.Union[np.ndarray, spmatrix], sign_mode: SignMode, loihi2: ty.Optional[bool] = False) -> OptimizedWeights: """Optimizes the weight matrix to best fit in Loihi's synapse. Parameters ---------- - weights : np.ndarray + weights : np.ndarray, spmatrix Standard 8-bit signed weight matrix. sign_mode : SignMode Determines whether the weights are purely excitatory, inhibitory, @@ -75,26 +76,29 @@ def optimize_weight_bits( weight_exp = _determine_weight_exp(weights, sign_mode) num_weight_bits = _determine_num_weight_bits(weights, weight_exp, sign_mode) - weights = np.left_shift(weights.astype(np.int32), int(-weight_exp)) + if isinstance(weights, np.ndarray): + weights = weights.astype(np.int32) << int(-weight_exp) + elif isinstance(weights, spmatrix): + weights.data = weights.data.astype(np.int32) << int(-weight_exp) if loihi2: - weights = weights // (1 << (8 - num_weight_bits)) + weights = (weights / (1 << (8 - num_weight_bits))).astype(np.int32) if sign_mode == SignMode.MIXED: - weights = weights // 2 + weights = (weights / 2).astype(np.int32) - optimized_weights = OptimizedWeights(weights=weights.astype(int), + optimized_weights = OptimizedWeights(weights=weights, num_weight_bits=num_weight_bits, weight_exp=weight_exp) return optimized_weights -def _validate_weights(weights: np.ndarray, +def _validate_weights(weights: ty.Union[np.ndarray, spmatrix], sign_mode: SignMode) -> None: """Validate the weight values against the given sign mode. Parameters ---------- - weights : numpy.ndarray + weights : numpy.ndarray, spmatrix Weight matrix sign_mode : SignMode Sign mode specified for the weight matrix @@ -107,11 +111,11 @@ def _validate_weights(weights: np.ndarray, min_weight += inhibitory_flag max_weight = (2 ** 8 - 1) * (mixed_flag + excitatory_flag) - if np.any(weights > max_weight) or np.any(weights < min_weight): + if weights.max() > max_weight or weights.min() < min_weight: raise ValueError(f"weights have to be between {min_weight} and " f"{max_weight} for {sign_mode=}. Got " - f"weights between {np.min(weights)} and " - f"{np.max(weights)}.") + f"weights between {weights.min()} and " + f"{weights.max()}.") def _determine_weight_exp(weights: np.ndarray, @@ -197,16 +201,17 @@ def _determine_num_weight_bits(weights: np.ndarray, return num_weight_bits -def truncate_weights(weights: np.ndarray, +def truncate_weights(weights: ty.Union[np.ndarray, spmatrix], sign_mode: SignMode, num_weight_bits: int, - max_num_weight_bits: ty.Optional[int] = 8) -> np.ndarray: + max_num_weight_bits: ty.Optional[int] = 8 + ) -> ty.Union[np.ndarray, spmatrix]: """Truncate the least significant bits of the weight matrix given the sign mode and number of weight bits. Parameters ---------- - weights : numpy.ndarray + weights : numpy.ndarray, spmatrix Weight matrix that is to be truncated. sign_mode : SignMode Sign mode to use for truncation. See SignMode class for the @@ -222,7 +227,7 @@ def truncate_weights(weights: np.ndarray, numpy.ndarray Truncated weight matrix. """ - weights = np.copy(weights).astype(np.int32) + weights = weights.copy().astype(np.int32) if sign_mode == SignMode.INHIBITORY: weights = -weights @@ -230,25 +235,27 @@ def truncate_weights(weights: np.ndarray, mixed_flag = int(sign_mode == SignMode.MIXED) num_truncate_bits = max_num_weight_bits - num_weight_bits + mixed_flag - truncated_weights = np.left_shift( - np.right_shift(weights, num_truncate_bits), - num_truncate_bits).astype(np.int32) + if isinstance(weights, np.ndarray): + weights = (weights >> num_truncate_bits) << num_truncate_bits + elif isinstance(weights, spmatrix): + weights.data = (weights.data >> num_truncate_bits) << num_truncate_bits + weights.eliminate_zeros() if sign_mode == SignMode.INHIBITORY: - truncated_weights = -truncated_weights + weights = -weights - return truncated_weights + return weights -def clip_weights(weights: np.ndarray, +def clip_weights(weights: ty.Union[np.ndarray, spmatrix], sign_mode: SignMode, - num_bits: int) -> np.ndarray: + num_bits: int) -> ty.Union[np.ndarray, spmatrix]: """Truncate the least significant bits of the weight matrix given the sign mode and number of weight bits. Parameters ---------- - weights : numpy.ndarray + weights : numpy.ndarray, spmatrix Weight matrix that is to be truncated. sign_mode : SignMode Sign mode to use for truncation. @@ -260,7 +267,7 @@ def clip_weights(weights: np.ndarray, numpy.ndarray Truncated weight matrix. """ - weights = np.copy(weights).astype(np.int32) + weights = weights.copy().astype(np.int32) mixed_flag = int(sign_mode == SignMode.MIXED) inhibitory_flag = int(sign_mode == SignMode.INHIBITORY) @@ -271,9 +278,13 @@ def clip_weights(weights: np.ndarray, min_wgt = (-2 ** num_bits) * mixed_flag max_wgt = 2 ** num_bits - 1 - clipped_weights = np.clip(weights, min_wgt, max_wgt) + if isinstance(weights, np.ndarray): + weights = np.clip(weights, min_wgt, max_wgt) + elif isinstance(weights, spmatrix): + weights[weights > max_wgt] = max_wgt + weights[weights < min_wgt] = min_wgt if inhibitory_flag: - clipped_weights = -clipped_weights + weights = -weights - return clipped_weights + return weights diff --git a/tests/lava/magma/compiler/subcompilers/py/test_pyproc_compiler.py b/tests/lava/magma/compiler/subcompilers/py/test_pyproc_compiler.py index 18b968c9c..e0f9c7c03 100644 --- a/tests/lava/magma/compiler/subcompilers/py/test_pyproc_compiler.py +++ b/tests/lava/magma/compiler/subcompilers/py/test_pyproc_compiler.py @@ -54,7 +54,6 @@ def __init__(self, **kwargs): class MockRuntimeService: __name__ = "MockRuntimeService" - pass # Define minimal Protocol to be implemented. @@ -124,7 +123,7 @@ def test_compile_py_proc_models(self): # There should be three PyProcessBuilders... self.assertEqual(len(builders), 3) - for proc, builder in builders.items(): + for builder in builders.values(): self.assertIsInstance(builder, PyProcessBuilder) # ... one for each Process. b1 = ty.cast(PyProcessBuilder, builders[p1]) diff --git a/tests/lava/magma/compiler/subcompilers/test_channel_builders_factory.py b/tests/lava/magma/compiler/subcompilers/test_channel_builders_factory.py index 5029096c6..5781ff14f 100644 --- a/tests/lava/magma/compiler/subcompilers/test_channel_builders_factory.py +++ b/tests/lava/magma/compiler/subcompilers/test_channel_builders_factory.py @@ -2,13 +2,11 @@ # SPDX-License-Identifier: BSD-3-Clause # See: https://spdx.org/licenses/ -from enum import Enum import logging import typing as ty import unittest from unittest.mock import Mock -import numpy as np from lava.magma.compiler.builders.channel_builder import ChannelBuilderMp from lava.magma.compiler.channel_map import ChannelMap, Payload, PortPair from lava.magma.runtime.message_infrastructure.interfaces import ChannelType @@ -16,9 +14,9 @@ from lava.magma.compiler.subcompilers.channel_builders_factory import \ ChannelBuildersFactory from lava.magma.compiler.utils import LoihiPortInitializer, PortInitializer -from lava.magma.compiler.var_model import LoihiAddress, LoihiVarModel from lava.magma.core.decorator import implements, requires from lava.magma.core.model.model import AbstractProcessModel +from lava.magma.core.model.interfaces import AbstractPortImplementation from lava.magma.core.model.py.model import AbstractPyProcessModel from lava.magma.core.model.py.ports import (PyInPort, PyOutPort, PyRefPort, PyVarPort, @@ -30,7 +28,7 @@ from lava.magma.core.process.ports.reduce_ops import ReduceSum from lava.magma.core.process.process import AbstractProcess from lava.magma.core.process.variable import Var -from lava.magma.core.resources import CPU, LMT, NeuroCore +from lava.magma.core.resources import CPU from lava.magma.core.run_configs import RunConfig from lava.magma.core.sync.protocol import AbstractSyncProtocol @@ -67,7 +65,6 @@ def __init__(self, **kwargs): class MockRuntimeService: __name__ = "MockRuntimeService" - pass # Define minimal Protocol to be implemented @@ -153,7 +150,7 @@ def __init__( def select(self, proc, proc_models): py_proc_model = None sub_proc_model = None - c_proc_model = None + # Find PyProcModel or SubProcModel for pm in proc_models: if issubclass(pm, AbstractSubProcessModel): @@ -161,7 +158,6 @@ def select(self, proc, proc_models): if issubclass(pm, AbstractPyProcessModel): py_proc_model = pm # Make selection - if self.select_sub_proc_model and sub_proc_model: return sub_proc_model if py_proc_model and not self.select_lmt: @@ -357,9 +353,6 @@ def test_create_channel_builders(self): channel_builders = self.factory.from_channel_map(channel_map, self.cfg) # This should result in 5 channel builders (one for each arrow above) - from lava.magma.compiler.builders.channel_builder import \ - ChannelBuilderMp - self.assertEqual(len(channel_builders), 5) for cb in channel_builders: self.assertIsInstance(cb, ChannelBuilderMp) diff --git a/tests/lava/magma/compiler/test_channel_map.py b/tests/lava/magma/compiler/test_channel_map.py index abce36844..43b2262c5 100644 --- a/tests/lava/magma/compiler/test_channel_map.py +++ b/tests/lava/magma/compiler/test_channel_map.py @@ -33,7 +33,6 @@ def __init__(self, **kwargs): class MockRuntimeService: __name__ = "MockRuntimeService" - pass # Define minimal Protocol to be implemented diff --git a/tests/lava/magma/compiler/test_compiler.py b/tests/lava/magma/compiler/test_compiler.py index 8d750218b..1046253c3 100644 --- a/tests/lava/magma/compiler/test_compiler.py +++ b/tests/lava/magma/compiler/test_compiler.py @@ -66,7 +66,6 @@ def __init__(self, **kwargs): class MockRuntimeService: __name__ = "MockRuntimeService" - pass # Define minimal Protocol to be implemented @@ -436,9 +435,6 @@ def test_extract_proc_builders(self) -> None: # Create some mock Processes. proc1 = Mock(spec_set=AbstractProcess) proc2 = Mock(spec_set=AbstractProcess) - proc3 = Mock(spec_set=AbstractProcess) - proc4 = Mock(spec_set=AbstractProcess) - proc5 = Mock(spec_set=AbstractProcess) # Create some Builders. py_builder1 = PyProcessBuilder(AbstractPyProcessModel, 0) diff --git a/tests/lava/magma/compiler/test_node.py b/tests/lava/magma/compiler/test_node.py index ea2bcfece..c23b84a07 100644 --- a/tests/lava/magma/compiler/test_node.py +++ b/tests/lava/magma/compiler/test_node.py @@ -12,8 +12,6 @@ class MockProcess(AbstractProcess): """A mock process""" - pass - class TestNode(unittest.TestCase): def test_node_creation(self): diff --git a/tests/lava/magma/core/learning/test_learning_rule.py b/tests/lava/magma/core/learning/test_learning_rule.py index 7b1384f00..4c2956553 100644 --- a/tests/lava/magma/core/learning/test_learning_rule.py +++ b/tests/lava/magma/core/learning/test_learning_rule.py @@ -7,30 +7,15 @@ from lava.magma.core.learning.learning_rule import ( LoihiLearningRule, - Loihi2FLearningRule, - Loihi3FLearningRule, + Loihi2FLearningRule ) from lava.magma.core.learning.product_series import ProductSeries from lava.magma.core.run_conditions import RunSteps from lava.magma.core.run_configs import Loihi2SimCfg -from lava.proc.lif.process import LIF, LearningLIF +from lava.proc.lif.process import LIF from lava.proc.dense.process import LearningDense, Dense from lava.proc.monitor.process import Monitor from lava.proc.io.source import RingBuffer as SpikeIn -from lava.magma.core.model.py.neuron import ( - LearningNeuronModelFloat, - LearningNeuronModelFixed, -) -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.proc.lif.models import ( - AbstractPyLifModelFloat, - AbstractPyLifModelFixed, -) -from lava.proc.io.source import RingBuffer as SpikeIn def create_network( diff --git a/tests/lava/magma/core/learning/test_random.py b/tests/lava/magma/core/learning/test_random.py index ecbc18cdd..21e6ad52b 100644 --- a/tests/lava/magma/core/learning/test_random.py +++ b/tests/lava/magma/core/learning/test_random.py @@ -3,7 +3,6 @@ # See: https://spdx.org/licenses/ import unittest -import numpy as np from lava.magma.core.learning.random import TraceRandom, ConnVarRandom diff --git a/tests/lava/magma/core/model/py/test_model.py b/tests/lava/magma/core/model/py/test_model.py index 34bab40d8..2af801fe6 100644 --- a/tests/lava/magma/core/model/py/test_model.py +++ b/tests/lava/magma/core/model/py/test_model.py @@ -13,7 +13,6 @@ PyLoihiProcessModel, PyLoihiModelToPyAsyncModel ) -from lava.proc import io from lava.proc.lif.process import LIF from lava.proc.sdn.process import SigmaDelta from lava.proc.dense.process import Dense @@ -127,10 +126,10 @@ def test_sdn_dense_sdn(self): 'state_exp': 6} dense_params = {'weights': weights, 'num_message_bits': 16} - input = SigmaDelta(**input_params) + input_ = SigmaDelta(**input_params) output = SigmaDelta(**output_params) dense = Dense(**dense_params) - input.s_out.connect(dense.s_in) + input_.s_out.connect(dense.s_in) dense.a_out.connect(output.a_in) run_cnd = RunSteps(num_steps=2) @@ -141,12 +140,12 @@ def test_sdn_dense_sdn(self): output.stop() # Run the same network in async mode. - # Currently we don't allow the same process to run twice + # Currently, we don't allow the same process to run twice # Copy the model used for pyproc model - input = SigmaDelta(**input_params) + input_ = SigmaDelta(**input_params) output = SigmaDelta(**output_params) dense = Dense(**dense_params) - input.s_out.connect(dense.s_in) + input_.s_out.connect(dense.s_in) dense.a_out.connect(output.a_in) output.run(condition=run_cnd, diff --git a/tests/lava/magma/core/model/test_decorators.py b/tests/lava/magma/core/model/test_decorators.py index 1c92e1665..a40cd74df 100644 --- a/tests/lava/magma/core/model/test_decorators.py +++ b/tests/lava/magma/core/model/test_decorators.py @@ -48,21 +48,21 @@ class TestProtocol(AbstractSyncProtocol): # We must pass a class, not an instance or anything else with self.assertRaises(TypeError): @implements(proc=TestProc(), protocol=TestProtocol) # type: ignore - class TestModel(AbstractProcessModel): # type: ignore + class TestModel(AbstractProcessModel): # pylint: disable=W0612 def run(self): pass # Same for 'protocol' with self.assertRaises(TypeError): @implements(proc=TestProc, protocol=TestProtocol()) # type: ignore - class TestModel2(AbstractProcessModel): + class TestModel2(AbstractProcessModel): # pylint: disable=W0612 def run(self): pass # And we can only decorate a subclass of 'AbstractProcessModel' with self.assertRaises(AssertionError): @implements(proc=TestProc, protocol=TestProtocol) - class TestProcess2(AbstractProcess): + class TestProcess2(AbstractProcess): # pylint: disable=W0612 pass def test_implements_subclassing(self): @@ -125,7 +125,7 @@ def run(self): # attributes must fail with self.assertRaises(AssertionError): @implements(protocol=TestProtocol2) - class SubTestModel(TestModel): + class SubTestModel(TestModel): # pylint: disable=W0612 pass def test_requires(self): @@ -190,7 +190,7 @@ def test_requires_failing(self): # We must decorate a ProcessModel and nothing else: with self.assertRaises(AssertionError): @requires(CPU) - class Something(AbstractProcess): + class Something(AbstractProcess): # pylint: disable=W0612 pass # We must decorate a ProcessModel with an 'AbstractResource' class @@ -198,7 +198,7 @@ class Something(AbstractProcess): with self.assertRaises(TypeError): @requires(CPU()) # type: ignore - class TestModel(AbstractProcessModel): + class TestModel(AbstractProcessModel): # pylint: disable=W0612 def run(self): pass @@ -241,20 +241,20 @@ def test_tags_failing(self): # Only decorating ProcessModels is allowed with self.assertRaises(AssertionError): @tag('some-tag') - class SomeClass(AbstractProcess): + class SomeClass(AbstractProcess): # pylint: disable=W0612 pass # Tags should be just comma-separated keywords with self.assertRaises(AssertionError): @tag('keyword1', ['keyword2', 'keyword3']) - class TestModel2(AbstractProcessModel): + class TestModel2(AbstractProcessModel): # pylint: disable=W0612 def run(self): pass # Tags should be just comma-separated keywords with self.assertRaises(AssertionError): @tag('tag1', [['tag2'], 'tag4']) - class SomeOtherClass(AbstractProcess): + class SomeOtherClass(AbstractProcess): # pylint: disable=W0612 pass diff --git a/tests/lava/magma/core/process/ports/test_ports.py b/tests/lava/magma/core/process/ports/test_ports.py index 33f155814..594dcaab2 100644 --- a/tests/lava/magma/core/process/ports/test_ports.py +++ b/tests/lava/magma/core/process/ports/test_ports.py @@ -290,7 +290,8 @@ class VarProcess(AbstractProcess): def test_connect_RefPort_to_Var_process_conflict(self): """Checks connecting RefPort implicitly to Var, with registered - processes and conflicting names. -> AssertionError""" + processes and conflicting names. -> adding _k with k=1,2,3... to + the name.""" # Create a mock parent process class VarProcess(AbstractProcess): @@ -307,9 +308,21 @@ class VarProcess(AbstractProcess): v.name = "existing_attr" # ... and connect it directly via connect_var(..) - # The naming conflict should raise an AssertionError - with self.assertRaises(AssertionError): - rp.connect_var(v) + rp.connect_var(v) + + # This has the same effect as connecting a RefPort explicitly via a + # VarPort to a Var... + self.assertEqual(rp.get_dst_vars(), [v]) + # ... but still creates a VarPort implicitly + vp = rp.get_dst_ports()[0] + self.assertIsInstance(vp, VarPort) + # ... which wraps the original Var + self.assertEqual(vp.var, v) + + # In this case, the VarPort inherits its name and parent process from + # the Var it wraps + _implicit_port + _k with k=1,2,3... + self.assertEqual(vp.name, "_" + v.name + "_implicit_port" + "_1") + self.assertEqual(vp.process, v.process) @unittest.skip("Currently not supported") def test_connect_RefPort_to_many_Vars(self): diff --git a/tests/lava/magma/core/process/test_lif_dense_lif.py b/tests/lava/magma/core/process/test_lif_dense_lif.py index 591214967..798c47fb9 100644 --- a/tests/lava/magma/core/process/test_lif_dense_lif.py +++ b/tests/lava/magma/core/process/test_lif_dense_lif.py @@ -29,11 +29,11 @@ def select(self, process, proc_models): class TestLifDenseLif(unittest.TestCase): def test_lif_dense_lif(self): - self.lif1 = LIF(shape=(1,)) - self.dense = Dense(weights=np.eye(1)) - self.lif2 = LIF(shape=(1,)) - self.lif1.out_ports.s_out.connect(self.dense.in_ports.s_in) - self.dense.out_ports.a_out.connect(self.lif2.in_ports.a_in) - self.lif1.run(condition=RunSteps(num_steps=10), - run_cfg=SimpleRunConfig(sync_domains=[])) - self.lif1.stop() + lif1 = LIF(shape=(1,)) + dense = Dense(weights=np.eye(1)) + lif2 = LIF(shape=(1,)) + lif1.out_ports.s_out.connect(dense.in_ports.s_in) + dense.out_ports.a_out.connect(lif2.in_ports.a_in) + lif1.run(condition=RunSteps(num_steps=10), + run_cfg=SimpleRunConfig(sync_domains=[])) + lif1.stop() diff --git a/tests/lava/magma/core/process/test_process.py b/tests/lava/magma/core/process/test_process.py index 8a33ad8fb..e2938874b 100644 --- a/tests/lava/magma/core/process/test_process.py +++ b/tests/lava/magma/core/process/test_process.py @@ -6,6 +6,9 @@ import unittest from unittest.mock import Mock, seal import typing as ty +from lava.magma.compiler.executable import Executable +from lava.magma.core.decorator import implements, requires +from lava.magma.core.model.py.model import AbstractPyProcessModel from lava.magma.core.process.ports.ports import ( InPort, @@ -20,7 +23,11 @@ ) from lava.magma.core.model.model import AbstractProcessModel from lava.magma.core.process.variable import Var +from lava.magma.core.resources import CPU from lava.magma.core.run_conditions import RunSteps +from lava.magma.core.run_configs import RunConfig +from lava.magma.core.sync.protocol import AbstractSyncProtocol +from lava.magma.runtime.runtime import Runtime class MinimalProcess(AbstractProcess): @@ -30,6 +37,34 @@ def __init__(self, name: ty.Optional[str] = None): super().__init__(name=name) +class MinimalRuntimeService: + __name__ = 'MinimalRuntimeService' + + def __init__(self): + pass + + +class MinimalProtocol(AbstractSyncProtocol): + @property + def runtime_service(self): + return {CPU: MinimalRuntimeService()} + + +@implements(proc=MinimalProcess, protocol=MinimalProtocol) +@requires(CPU) +class MinimalPyProcessModel(AbstractPyProcessModel): + def run(self): + raise NotImplementedError('This model doesnt run') + + +class MinimalRunConfig(RunConfig): + def __init__(self): + super().__init__(custom_sync_domains=None, loglevel=logging.WARNING) + + def select(self, proc, proc_models): + return proc_models[0] + + class TestCollection(unittest.TestCase): def setUp(self): """Reset ProcessServer before each test.""" @@ -259,13 +294,33 @@ class TestProcess(unittest.TestCase): def test_model_property(self) -> None: """Tests whether the ProcessModel of a Process can be obtained through a property method.""" - p = MinimalProcess() p._model_class = Mock(spec_set=AbstractProcessModel) seal(p._model_class) - self.assertIsInstance(p.model_class, AbstractProcessModel) + def test_compile(self) -> None: + """Test whether compile creates an executable which is ready + to build the process model for a simple process.""" + p = MinimalProcess() + run_cfg = MinimalRunConfig() + e = p.compile(run_cfg) + self.assertIsInstance(e, Executable) + self.assertEqual(len(e.proc_builders), 1) + + @unittest.skip("This case cannot run becase the MinimalPyProcessModel") + def test_create_runtime(self) -> None: + """Tests the create_runtime method.""" + p = MinimalProcess() + self.assertIsNone(p.runtime) + run_cfg = MinimalRunConfig() + p.create_runtime(run_cfg) + r = p.runtime + self.assertIsInstance(r, Runtime) + self.assertTrue(r._is_initialized) + self.assertFalse(r._is_started) + self.assertFalse(r._is_running) + def test_run_without_run_config_raises_error(self) -> None: """Tests whether an error is raised when run() is called on uncompiled Processes without specifying a RunConfig.""" diff --git a/tests/lava/magma/runtime/test_async_protocol.py b/tests/lava/magma/runtime/test_async_protocol.py index 0cf3152ee..98e02c857 100644 --- a/tests/lava/magma/runtime/test_async_protocol.py +++ b/tests/lava/magma/runtime/test_async_protocol.py @@ -68,7 +68,7 @@ def test_async_process_model(self): Verifies the working of Asynchronous Process """ process = AsyncProcess1(shape=(2, 2)) - simple_sync_domain = SyncDomain("simple", AsyncProtocol(), [process]) + _ = SyncDomain("simple", AsyncProtocol(), [process]) process.run(condition=RunContinuous(), run_cfg=Loihi2SimCfg()) process.stop() @@ -78,7 +78,7 @@ def test_async_process_model_pause(self): effect """ process = AsyncProcess1(shape=(2, 2)) - simple_sync_domain = SyncDomain("simple", AsyncProtocol(), [process]) + _ = SyncDomain("simple", AsyncProtocol(), [process]) process.run(condition=RunContinuous(), run_cfg=Loihi2SimCfg()) process.pause() process.stop() @@ -89,7 +89,7 @@ def test_async_process_num_steps(self): implicitly passed as num_steps for the process. """ process = AsyncProcess2(shape=(2, 2)) - simple_sync_domain = SyncDomain("simple", AsyncProtocol(), [process]) + _ = SyncDomain("simple", AsyncProtocol(), [process]) process.run(condition=RunSteps(num_steps=10), run_cfg=Loihi2SimCfg()) process.stop() @@ -99,7 +99,7 @@ def test_async_process_get(self): of the variable after run finishes. """ process = AsyncProcess2(shape=(2, 2)) - simple_sync_domain = SyncDomain("simple", AsyncProtocol(), [process]) + _ = SyncDomain("simple", AsyncProtocol(), [process]) process.run(condition=RunSteps(num_steps=10), run_cfg=Loihi2SimCfg()) print(process.u.get()) process.stop() diff --git a/tests/lava/magma/runtime/test_get_set_non_determinism.py b/tests/lava/magma/runtime/test_get_set_non_determinism.py index d9c6fc295..b5fce8f56 100644 --- a/tests/lava/magma/runtime/test_get_set_non_determinism.py +++ b/tests/lava/magma/runtime/test_get_set_non_determinism.py @@ -42,7 +42,7 @@ class TestNonDeterminismUpdate(unittest.TestCase): def test_non_determinism_update(self): nb_runs = 10000 demo_process = DemoProcess(nb_runs=nb_runs) - for i in range(nb_runs): + for _ in range(nb_runs): demo_process.run(condition=RunSteps(num_steps=1), run_cfg=Loihi1SimCfg()) diff --git a/tests/lava/magma/runtime/test_loihi_with_async_protocol.py b/tests/lava/magma/runtime/test_loihi_with_async_protocol.py index 634b0be84..8c6865b18 100644 --- a/tests/lava/magma/runtime/test_loihi_with_async_protocol.py +++ b/tests/lava/magma/runtime/test_loihi_with_async_protocol.py @@ -18,11 +18,6 @@ from lava.magma.core.sync.protocols.async_protocol import AsyncProtocol from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol -""" -This test checks if Process with Loihi Protocol works properly with -process with Async Protocol. -""" - class AsyncProcessDest(AbstractProcess): def __init__(self, **kwargs): @@ -92,6 +87,10 @@ def run_spk(self): class TestProcess(unittest.TestCase): + """This test checks if Process with Loihi Protocol works properly with + process with Async Protocol. + """ + def test_async_with_loihi_protocol(self): """ Test is to send the data to AsyncProcessSrc from AsyncProcessSrc via diff --git a/tests/lava/proc/conv/test_utils.py b/tests/lava/proc/conv/test_utils.py index 4542973b5..ac1e8b2f5 100644 --- a/tests/lava/proc/conv/test_utils.py +++ b/tests/lava/proc/conv/test_utils.py @@ -36,7 +36,7 @@ def test_conv(self) -> None: kernel_size[0], kernel_size[1], in_channels // groups] weights = np.random.randint(256, size=weight_dims) - 128 - input = np.random.random( + input_ = np.random.random( ( # input needs to be a certain size # to make sure the output dimension is never negative @@ -45,13 +45,13 @@ def test_conv(self) -> None: + [in_channels] ) - out = utils.conv_scipy(input, weights, kernel_size, + out = utils.conv_scipy(input_, weights, kernel_size, stride, padding, dilation, groups) if compare: # if torch is available, compare against it. out_gt = F.conv2d( torch.unsqueeze( # torch expects a batch dimension NCHW - torch.FloatTensor(input.transpose([2, 1, 0])), + torch.FloatTensor(input_.transpose([2, 1, 0])), dim=0, ), torch.FloatTensor( @@ -70,7 +70,7 @@ def test_conv(self) -> None: error = np.abs(out - out_gt).mean() if error >= 1e-3: # small eps to account for float/double calc # Setting failed! Print out the dimensions for debugging. - print(f'{input.shape=}') + print(f'{input_.shape=}') print(f'{weights.shape=}') print(f'{kernel_size=}') print(f'{stride=}') diff --git a/tests/lava/proc/dense/test_learning.py b/tests/lava/proc/dense/test_learning.py index b3d8de32d..77886771e 100644 --- a/tests/lava/proc/dense/test_learning.py +++ b/tests/lava/proc/dense/test_learning.py @@ -697,8 +697,9 @@ def test_learning_graded_spike_reg_imp_bit_approx_y0_condition(self): learning_rule_cnd = "y0" graded_spike_cfg = GradedSpikeCfg.USE_REGULAR_IMPULSE - pre_ring_buffer, learning_dense, _ = \ - self.create_network(num_steps, learning_rule_cnd, graded_spike_cfg) + pre_ring_buffer, dense, _ = self.create_network(num_steps, + learning_rule_cnd, + graded_spike_cfg) # x1 updates with decayed regular impulse, at the end of the epoch expected_x1_data = [0.0, 0.0, 0.0, 14.0, 14.0] @@ -714,9 +715,9 @@ def test_learning_graded_spike_reg_imp_bit_approx_y0_condition(self): pre_ring_buffer.run(condition=self._run_cnd, run_cfg=self._run_cfg) - x1_data.append(learning_dense.x1.get()[0]) - x2_data.append(learning_dense.x2.get()[0]) - wgt_data.append(learning_dense.weights.get()[0, 0]) + x1_data.append(dense.x1.get()[0]) + x2_data.append(dense.x2.get()[0]) + wgt_data.append(dense.weights.get()[0, 0]) pre_ring_buffer.stop() diff --git a/tests/lava/proc/dense/test_models.py b/tests/lava/proc/dense/test_models.py index ed2baafab..467e3de1c 100644 --- a/tests/lava/proc/dense/test_models.py +++ b/tests/lava/proc/dense/test_models.py @@ -568,7 +568,7 @@ def test_matrix_weight_delay_expansion(self): delays = np.zeros(shape, dtype=int) delays[2, 2] = 2 max_delay = np.max(delays) - wgt_dly = AbstractPyDelayDenseModel.get_del_wgts(weights, delays) + wgt_dly = AbstractPyDelayDenseModel.get_delay_wgts_mat(weights, delays) # Expected shape is maximum delay=2 + 1 = 3 times first dimension of # original shape (3, 4) => (9, 4) expected_shape = ((max_delay + 1) * 3, 4) diff --git a/tests/lava/proc/io/test_dataloader.py b/tests/lava/proc/io/test_dataloader.py index e12514244..6e72fae47 100644 --- a/tests/lava/proc/io/test_dataloader.py +++ b/tests/lava/proc/io/test_dataloader.py @@ -50,20 +50,20 @@ def __init__(self, shape: tuple, dtype: np.dtype) -> None: def __len__(self) -> int: return 10 - def __getitem__(self, id: int) -> Tuple[np.ndarray, int]: - data = np.arange(np.prod(self.shape)).reshape(self.shape) + id + def __getitem__(self, id_: int) -> Tuple[np.ndarray, int]: + data = np.arange(np.prod(self.shape)).reshape(self.shape) + id_ data = data % np.prod(self.shape) data = data.astype(self.dtype) - label = id + label = id_ return data, label class SpikeDataset(DummyDataset): - def __getitem__(self, id: int) -> Tuple[np.ndarray, int]: - data = np.arange(np.prod(self.shape)).reshape(self.shape[::-1]) + id + def __getitem__(self, id_: int) -> Tuple[np.ndarray, int]: + data = np.arange(np.prod(self.shape)).reshape(self.shape[::-1]) + id_ data = data.transpose(np.arange(len(self.shape))[::-1]) % 13 data = data >= 10 - label = id + label = id_ return data, label diff --git a/tests/lava/proc/io/test_source_sink.py b/tests/lava/proc/io/test_source_sink.py index b800601d6..134706572 100644 --- a/tests/lava/proc/io/test_source_sink.py +++ b/tests/lava/proc/io/test_source_sink.py @@ -38,11 +38,11 @@ def test_source_sink(self) -> None: """Test whatever is being sent form source is received at sink.""" num_steps = 10 shape = (64, 64, 16) - input = np.random.randint(256, size=shape + (num_steps,)) - input -= 128 + input_ = np.random.randint(256, size=shape + (num_steps,)) + input_ -= 128 # input = 0.5 * input - source = SendProcess(data=input) + source = SendProcess(data=input_) sink = ReceiveProcess(shape=shape, buffer=num_steps) source.out_ports.s_out.connect(sink.in_ports.a_in) @@ -53,8 +53,8 @@ def test_source_sink(self) -> None: sink.stop() self.assertTrue( - np.all(output == input), + np.all(output == input_), f'Input and Ouptut do not match.\n' - f'{output[output!=input]=}\n' - f'{input[output!=input] =}\n' + f'{output[output!=input_]=}\n' + f'{input_[output!=input_] =}\n' ) diff --git a/tests/lava/proc/lif/test_models.py b/tests/lava/proc/lif/test_models.py index e5d03126a..d9ec66528 100644 --- a/tests/lava/proc/lif/test_models.py +++ b/tests/lava/proc/lif/test_models.py @@ -1,9 +1,10 @@ -# Copyright (C) 2021-22 Intel Corporation +# Copyright (C) 2021-23 Intel Corporation # SPDX-License-Identifier: BSD-3-Clause # See: https://spdx.org/licenses/ import unittest import numpy as np +from numpy.testing import assert_almost_equal from lava.magma.core.decorator import implements, requires, tag from lava.magma.core.model.py.model import PyLoihiProcessModel @@ -13,10 +14,10 @@ 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 Loihi1SimCfg, Loihi2SimCfg, RunConfig +from lava.magma.core.run_configs import Loihi2SimCfg, RunConfig from lava.magma.core.run_conditions import RunSteps from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol -from lava.proc.lif.process import LIF, LIFReset, TernaryLIF +from lava.proc.lif.process import LIF, LIFReset, TernaryLIF, LIFRefractory from lava.proc import io @@ -244,7 +245,7 @@ def test_float_pm_impulse_dv(self): rcfg = LifRunConfig(select_tag='floating_pt') lif_v = [] # Run 1 timestep at a time and collect state variable u - for j in range(num_steps): + for _ in range(num_steps): lif.run(condition=rcnd, run_cfg=rcfg) lif_v.append(lif.v.get()[0]) lif.stop() @@ -393,7 +394,6 @@ def test_bitacc_pm_scaling_of_bias(self): """ Tests fixed point LIF ProcessModel's scaling of threshold. """ - num_steps = 1 bias_mant = 2 ** 12 - 1 bias_exp = 5 # Set up high threshold and high bias current to check for potential @@ -825,3 +825,37 @@ def test_fixed_model(self): self.assertTrue(np.array_equal(u[:, reset_offset - 1:], u_gt_post)) self.assertTrue(np.array_equal(v[:, :reset_offset - 1], v_gt_pre)) self.assertTrue(np.array_equal(v[:, reset_offset - 1:], v_gt_post)) + + +class TestLIFRefractory(unittest.TestCase): + """Test LIF Refractory process model""" + + def test_float_model(self): + """Test float model""" + num_neurons = 2 + num_steps = 8 + refractory_period = 1 + + # Two neurons with different biases + lif_refractory = LIFRefractory(shape=(num_neurons,), + u=np.arange(num_neurons), + bias_mant=np.arange(num_neurons) + 1, + bias_exp=np.ones( + (num_neurons,), dtype=float), + vth=4., + refractory_period=refractory_period) + + v_logger = io.sink.Read(buffer=num_steps) + v_logger.connect_var(lif_refractory.v) + + lif_refractory.run(condition=RunSteps(num_steps), + run_cfg=Loihi2SimCfg(select_tag="floating_pt")) + + v = v_logger.data.get() + lif_refractory.stop() + + # 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) + + assert_almost_equal(v, v_expected) diff --git a/tests/lava/proc/rf/test_models.py b/tests/lava/proc/rf/test_models.py index 50906f419..a89a66a67 100644 --- a/tests/lava/proc/rf/test_models.py +++ b/tests/lava/proc/rf/test_models.py @@ -67,15 +67,15 @@ def run_test( self, period: float, alpha: float, - input: np.ndarray, + input_: np.ndarray, state_exp: int = 0, decay_bits: int = 0, vth: float = 1, tag: str = 'floating_pt', ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: - input = np.int32(input.reshape(1, -1)) - num_steps = input.size - source = io.source.RingBuffer(data=input) + input_ = np.int32(input_.reshape(1, -1)) + num_steps = input_.size + source = io.source.RingBuffer(data=input_) rf = RF(shape=(1,), period=period, alpha=alpha, @@ -102,7 +102,7 @@ def run_test( imag = imag_monitor.get_data()[rf.name]["imag"] rf.stop() - return input, real, imag, s_out + return input_, real, imag, s_out def test_float_no_decay(self): """Verify that a neuron with no voltage decay spikes @@ -112,9 +112,9 @@ def test_float_no_decay(self): alpha = 0 num_steps = 100 - input = np.zeros(num_steps) - input[0] = 1.1 # spike at first timestep - _, _, _, s_out = self.run_test(period, alpha, input) + input_ = np.zeros(num_steps) + input_[0] = 1.1 # spike at first timestep + _, _, _, s_out = self.run_test(period, alpha, input_) # observe differences in spike times spike_idx = np.argwhere(s_out[0, :]) @@ -134,9 +134,9 @@ def test_float_decay(self): vth = 1.1 num_steps = 100 - input = np.zeros(num_steps) - input[0] = 1 # spike at first timestep - _, real, _, _ = self.run_test(period, alpha, input, vth=vth) + input_ = np.zeros(num_steps) + input_[0] = 1 # spike at first timestep + _, real, _, _ = self.run_test(period, alpha, input_, vth=vth) ideal_real = np.round((1 - alpha)**np.arange(num_steps), 6) round_real = np.round(real.flatten(), 6) @@ -155,10 +155,10 @@ def test_fixed_pm_no_decay(self): period = 10 num_steps = 100 - input = np.zeros(num_steps) - input[0] = 1 # spike at first timestep + input_ = np.zeros(num_steps) + input_[0] = 1 # spike at first timestep - _, _, _, s_out = self.run_test(period, alpha, input, vth=vth, + _, _, _, s_out = self.run_test(period, alpha, input_, vth=vth, state_exp=state_exp, decay_bits=decay_bits, tag="fixed_pt") @@ -173,7 +173,7 @@ def test_fixed_pm_no_decay(self): # Run Test RF Dynamics real, imag = rf_dynamics(0, 0, sin_decay, cos_decay, - input * (1 << state_exp), + input_ * (1 << state_exp), np.zeros(num_steps), decay_bits) @@ -197,10 +197,10 @@ def test_fixed_pm_decay1(self): period = 10 num_steps = 100 - input = np.zeros(num_steps) - input[0] = 2 # spike at first timestep + input_ = np.zeros(num_steps) + input_[0] = 2 # spike at first timestep - _, _, _, s_out = self.run_test(period, alpha, input, vth=vth, + _, _, _, s_out = self.run_test(period, alpha, input_, vth=vth, state_exp=state_exp, decay_bits=decay_bits, tag="fixed_pt") @@ -215,7 +215,7 @@ def test_fixed_pm_decay1(self): # Run Test RF Dynamics real, imag = rf_dynamics(0, 0, sin_decay, cos_decay, - input * (1 << state_exp), + input_ * (1 << state_exp), np.zeros(num_steps), decay_bits) @@ -248,12 +248,12 @@ def test_fixed_pm_decay2(self): cos_decay = int(cos_decay * (1 << decay_bits)) num_steps = 100 - input = np.zeros(num_steps) - input[0] = 1 # spike at first timestep + input_ = np.zeros(num_steps) + input_[0] = 1 # spike at first timestep decay_bits = 12 state_exp = 6 - _, real, _, _ = self.run_test(period, alpha, input, vth=vth, + _, real, _, _ = self.run_test(period, alpha, input_, vth=vth, state_exp=state_exp, decay_bits=decay_bits, tag="fixed_pt") diff --git a/tests/lava/proc/rf_iz/test_models.py b/tests/lava/proc/rf_iz/test_models.py index c1c8a56e4..12e5621db 100644 --- a/tests/lava/proc/rf_iz/test_models.py +++ b/tests/lava/proc/rf_iz/test_models.py @@ -20,15 +20,15 @@ def run_test( self, period: float, alpha: float, - input: np.ndarray, + input_: np.ndarray, state_exp: int = 0, decay_bits: int = 0, vth: float = 1, tag: str = 'floating_pt', ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: - input = input.reshape(1, -1) - num_steps = input.size - source = io.source.RingBuffer(data=input) + input_ = input_.reshape(1, -1) + num_steps = input_.size + source = io.source.RingBuffer(data=input_) rf = RF_IZ(shape=(1,), period=period, alpha=alpha, @@ -55,7 +55,7 @@ def run_test( imag = imag_monitor.get_data()[rf.name]["imag"] rf.stop() - return input, real, imag, s_out + return input_, real, imag, s_out def test_float_reset(self): """Ensure that spikes events are followed by proper rf_iz reset @@ -65,9 +65,9 @@ def test_float_reset(self): eps = 1e-5 num_steps = 100 - input = np.zeros(num_steps) - input[[0, 10, 20]] = 1 # Will ensure 3 spikes - _, real, imag, s_out = self.run_test(period, alpha, input) + input_ = np.zeros(num_steps) + input_[[0, 10, 20]] = 1 # Will ensure 3 spikes + _, real, imag, s_out = self.run_test(period, alpha, input_) s_out = s_out.flatten() == 1 # change to bool self.assertGreaterEqual(s_out.sum(), 1) # ensure network is spiking self.assertListEqual(real.flatten()[s_out].tolist(), @@ -84,9 +84,9 @@ def test_fixed_pm_reset(self): eps = 1 # in fixed point 1 is the smallest value we can have state_exp = 6 num_steps = 100 - input = np.zeros(num_steps) - input[[0, 10, 20]] = 1 # Will ensure 3 spikes - _, real, imag, s_out = self.run_test(period, alpha, input, + input_ = np.zeros(num_steps) + input_[[0, 10, 20]] = 1 # Will ensure 3 spikes + _, real, imag, s_out = self.run_test(period, alpha, input_, tag="fixed_pt", state_exp=state_exp, decay_bits=12) diff --git a/tests/lava/proc/sdn/test_models.py b/tests/lava/proc/sdn/test_models.py index 3c59f839b..be86f1ea1 100644 --- a/tests/lava/proc/sdn/test_models.py +++ b/tests/lava/proc/sdn/test_models.py @@ -24,13 +24,13 @@ def run_test( num_steps: int, tag: str = 'fixed_pt' ) -> Tuple[np.ndarray, np.ndarray]: - input = np.sin(0.1 * np.arange(num_steps).reshape(1, -1)) + input_ = np.sin(0.1 * np.arange(num_steps).reshape(1, -1)) if tag == 'fixed_pt': - input *= (1 << 12) - input = input.astype(int) - input[:, 1:] -= input[:, :-1] + input_ *= (1 << 12) + input_ = input_.astype(int) + input_[:, 1:] -= input_[:, :-1] - source = io.source.RingBuffer(data=input) + source = io.source.RingBuffer(data=input_) sigma = Sigma(shape=(1,)) sink = io.sink.RingBuffer(shape=sigma.shape, buffer=num_steps) @@ -44,18 +44,18 @@ def run_test( output = sink.data.get() sigma.stop() - return input, output + return input_, output def test_sigma_decoding_fixed(self) -> None: """Test sigma decoding with cumulative sum.""" num_steps = 100 - input, output = self.run_test( + input_, output = self.run_test( num_steps=num_steps, tag='fixed_pt' ) - error = np.abs(np.cumsum(input, axis=1) - output).max() + error = np.abs(np.cumsum(input_, axis=1) - output).max() if verbose: print(f'Max abs error = {error}') @@ -65,12 +65,12 @@ def test_sigma_decoding_float(self) -> None: """Test sigma decoding with cumulative sum.""" num_steps = 100 - input, output = self.run_test( + input_, output = self.run_test( num_steps=num_steps, tag='floating_pt' ) - error = np.abs(np.cumsum(input, axis=1) - output).max() + error = np.abs(np.cumsum(input_, axis=1) - output).max() if verbose: print(f'Max abs error = {error}') @@ -90,11 +90,11 @@ def run_test( cum_error: bool, tag: str = 'fixed_pt', ) -> Tuple[np.ndarray, np.ndarray]: - input = np.sin(0.1 * np.arange(num_steps).reshape(1, -1)) - input *= (1 << spike_exp + state_exp) - input[:, 1:] -= input[:, :-1] + input_ = np.sin(0.1 * np.arange(num_steps).reshape(1, -1)) + input_ *= (1 << spike_exp + state_exp) + input_[:, 1:] -= input_[:, :-1] - source = io.source.RingBuffer(data=input.astype(int) * (1 << 6)) + source = io.source.RingBuffer(data=input_.astype(int) * (1 << 6)) sdn = SigmaDelta( shape=(1,), vth=vth, @@ -115,10 +115,10 @@ def run_test( output = sink.data.get() sdn.stop() - input = np.cumsum(input, axis=1) + input_ = np.cumsum(input_, axis=1) output = np.cumsum(output, axis=1) - return input, output + return input_, output def test_reconstruction_fixed(self) -> None: """Tests fixed point sigma delta reconstruction. The max absolute @@ -128,7 +128,7 @@ def test_reconstruction_fixed(self) -> None: spike_exp = 6 state_exp = 6 vth = 10 << (spike_exp + state_exp) - input, output = self.run_test( + input_, output = self.run_test( num_steps=num_steps, vth=vth, act_mode=ActivationMode.UNIT, @@ -137,7 +137,7 @@ def test_reconstruction_fixed(self) -> None: cum_error=False, ) - error = np.abs(input - output).max() + error = np.abs(input_ - output).max() if verbose: print(f'Max abs error = {error}') @@ -151,7 +151,7 @@ def test_reconstruction_float(self) -> None: spike_exp = 0 state_exp = 0 vth = 10 - input, output = self.run_test( + input_, output = self.run_test( num_steps=num_steps, vth=vth, act_mode=ActivationMode.UNIT, @@ -161,7 +161,7 @@ def test_reconstruction_float(self) -> None: tag='floating_pt' ) - error = np.abs(input - output).max() + error = np.abs(input_ - output).max() if verbose: print(f'Max abs error = {error}') @@ -175,7 +175,7 @@ def test_reconstruction_cum_error_fixed(self) -> None: spike_exp = 6 state_exp = 6 vth = 10 << (spike_exp + state_exp) - input, output = self.run_test( + input_, output = self.run_test( num_steps=num_steps, vth=vth, act_mode=ActivationMode.UNIT, @@ -184,7 +184,7 @@ def test_reconstruction_cum_error_fixed(self) -> None: cum_error=True, ) - error = np.abs(input - output).max() + error = np.abs(input_ - output).max() if verbose: print(f'Max abs error = {error}') @@ -198,7 +198,7 @@ def test_reconstruction_cum_error_float(self) -> None: spike_exp = 0 state_exp = 0 vth = 10 - input, output = self.run_test( + input_, output = self.run_test( num_steps=num_steps, vth=vth, act_mode=ActivationMode.UNIT, @@ -208,7 +208,7 @@ def test_reconstruction_cum_error_float(self) -> None: tag='floating_pt' ) - error = np.abs(input - output).max() + error = np.abs(input_ - output).max() if verbose: print(f'Max abs error = {error}') @@ -222,7 +222,7 @@ def test_reconstruction_relu_fixed(self) -> None: spike_exp = 0 state_exp = 0 vth = 10 << (spike_exp + state_exp) - input, output = self.run_test( + input_, output = self.run_test( num_steps=num_steps, vth=vth, act_mode=ActivationMode.RELU, @@ -231,7 +231,7 @@ def test_reconstruction_relu_fixed(self) -> None: cum_error=False, ) - error = np.abs(np.maximum(input, 0) - output).max() + error = np.abs(np.maximum(input_, 0) - output).max() if verbose: print(f'Max abs error = {error}') @@ -245,7 +245,7 @@ def test_reconstruction_relu_float(self) -> None: vth = 10 spike_exp = 0 state_exp = 0 - input, output = self.run_test( + input_, output = self.run_test( num_steps=num_steps, vth=vth, act_mode=ActivationMode.RELU, @@ -255,7 +255,7 @@ def test_reconstruction_relu_float(self) -> None: tag='floating_pt', ) - error = np.abs(np.maximum(input, 0) - output).max() + error = np.abs(np.maximum(input_, 0) - output).max() if verbose: print(f'Max abs error = {error}') diff --git a/tests/lava/proc/sparse/__init__.py b/tests/lava/proc/sparse/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/lava/proc/sparse/test_models.py b/tests/lava/proc/sparse/test_models.py new file mode 100644 index 000000000..5f045df6b --- /dev/null +++ b/tests/lava/proc/sparse/test_models.py @@ -0,0 +1,1449 @@ +# Copyright (C) 2023 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# See: https://spdx.org/licenses/ + +import unittest +import numpy as np +from lava.magma.core.learning.learning_rule import Loihi2FLearningRule +from scipy.sparse import csr_matrix + +from lava.proc.dense.process import LearningDense +from lava.proc.sparse.process import Sparse, DelaySparse, LearningSparse +from lava.proc.learning_rules.stdp_learning_rule import STDPLoihi +from lava.proc.dense.process import Dense +from lava.proc.sparse.models import AbstractPyDelaySparseModel as APDSM +from lava.proc.io.source import RingBuffer as Source +from lava.proc.io.sink import RingBuffer as Sink + +from lava.magma.core.run_configs import Loihi2SimCfg +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_conditions import RunSteps +from lava.magma.core.sync.protocols.loihi_protocol import LoihiProtocol +from lava.proc.dense.models import AbstractPyDelayDenseModel +from lava.utils.weightutils import SignMode + + +def create_network(input_data, conn, weights): + source = Source(data=input_data) + sink = Sink(shape=(weights.shape[0], ), + buffer=input_data.shape[1]) + + source.s_out.connect(conn.s_in) + conn.a_out.connect(sink.a_in) + + return source, conn, sink + + +def create_learning_network(data_pre, conn, data_post, weights=None): + pre = Source(data=data_pre) + post = Source(data=data_post) + + if weights is not None: + sink = Sink(shape=(weights.shape[0], ), + buffer=data_post.shape[1]) + + conn.a_out.connect(sink.a_in) + + pre.s_out.connect(conn.s_in) + post.s_out.connect(conn.s_in_bap) + + if weights is not None: + return pre, conn, post, sink + else: + return pre, conn, post + + +class TestSparseProcessModelFloat(unittest.TestCase): + """Tests for Sparse class in floating point precision. """ + + def test_consistency_with_dense_random_shape(self): + """Tests if the results of Sparse and Dense are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 300, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + + # Sparsify + weights[np.abs(weights) < 0.7] = 0 + + inp = (np.random.rand(shape[1], simtime) > 0.7).astype(int) + + conn = Dense(weights=weights) + dense_net = create_network(inp, conn, weights) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + # Weights_got_dense = conn.weights.get() + result_dense = dense_net[2].data.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = Sparse(weights=weights_sparse) + sparse_net = create_network(inp, conn, weights_sparse) + conn.run(condition=run_cond, run_cfg=run_cfg) + + # Weights_got_sparse = conn.weights.get() + result_sparse = sparse_net[2].data.get() + conn.stop() + + np.testing.assert_array_almost_equal(result_sparse, result_dense) + + def test_consistency_with_dense_random_shape_graded(self): + """Tests if the results of Sparse and Dense are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 300, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + + # Sparsify + weights[np.abs(weights) < 0.7] = 0 + + inp = (np.random.rand(shape[1], simtime) * 10).astype(int) + + conn = Dense(weights=weights, num_message_bits=8) + dense_net = create_network(inp, conn, weights) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + dense_net[0].run(condition=run_cond, run_cfg=run_cfg) + result_dense = dense_net[2].data.get() + dense_net[0].stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = Sparse(weights=weights_sparse, num_message_bits=8) + sparse_net = create_network(inp, conn, weights_sparse) + sparse_net[0].run(condition=run_cond, run_cfg=run_cfg) + + result_sparse = sparse_net[2].data.get() + sparse_net[0].stop() + + np.testing.assert_array_almost_equal(result_sparse, result_dense) + + def test_weights_get(self): + """Tests the get method on weights.""" + + simtime = 10 + shape = np.random.randint(1, 300, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + + # Sparsify + weights[np.abs(weights) < 0.7] = 0 + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + inp = (np.random.rand(shape[1], simtime) * 10).astype(int) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn = Sparse(weights=weights_sparse) + create_network(inp, conn, weights_sparse) + conn.run(condition=run_cond, run_cfg=run_cfg) + + weights_got = conn.weights.get() + conn.stop() + + self.assertIsInstance(weights_got, csr_matrix) + np.testing.assert_array_equal(weights_got.toarray(), weights) + + def test_weights_set(self): + """Tests the set method on weights.""" + simtime = 2 + shape = np.random.randint(1, 300, 2).tolist() + weights_init = (np.random.random(shape) - 0.5) * 2 + + # Sparsify + weights_init[np.abs(weights_init) < 0.7] = 0 + weights_init_sparse = csr_matrix(weights_init) + + new_weights_sparse = weights_init_sparse.copy() + new_weights_sparse.data = (np.random.random( + new_weights_sparse.data.shape) - 0.5) * 2 + + inp = (np.random.rand(shape[1], simtime) * 10).astype(int) + + run_cond = RunSteps(num_steps=1) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn = Sparse(weights=weights_init_sparse) + create_network(inp, conn, weights_init_sparse) + conn.run(condition=run_cond, run_cfg=run_cfg) + + new_weights_sparse = conn.weights.init.copy() + new_weights_sparse.data = np.random.permutation(new_weights_sparse.data) + + conn.weights.set(new_weights_sparse) + + conn.run(condition=run_cond, run_cfg=run_cfg) + + weights_got_ts_2 = conn.weights.get() + + conn.stop() + + self.assertIsInstance(weights_got_ts_2, csr_matrix) + np.testing.assert_array_equal(weights_got_ts_2.toarray(), + new_weights_sparse.toarray()) + + +class TestSparseProcessModelFixed(unittest.TestCase): + """Tests for Sparse class in fixed point precision. """ + + def test_consitency_with_dense_random_shape(self): + """Tests if the results of Sparse and Dense are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 300, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + + # Sparsify + weights[np.abs(weights) < 0.7] = 0 + weights *= 20 + weights = weights.astype(int) + + inp = (np.random.rand(shape[1], simtime) > 0.7).astype(int) + + conn = Dense(weights=weights) + dense_net = create_network(inp, conn, weights) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='fixed_pt') + + dense_net[0].run(condition=run_cond, run_cfg=run_cfg) + result_dense = dense_net[2].data.get() + dense_net[0].stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = Sparse(weights=weights_sparse) + sparse_net = create_network(inp, conn, weights_sparse) + sparse_net[0].run(condition=run_cond, run_cfg=run_cfg) + + result_sparse = sparse_net[2].data.get() + sparse_net[0].stop() + + np.testing.assert_array_almost_equal(result_sparse, result_dense) + + def test_consitency_with_dense_random_shape_graded(self): + """Tests if the results of Sparse and Dense are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 300, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + + # Sparsify + weights[np.abs(weights) < 0.7] = 0 + weights *= 20 + weights = weights.astype(int) + + inp = (np.random.rand(shape[1], simtime) * 10).astype(int) + + conn = Dense(weights=weights, num_message_bits=8) + dense_net = create_network(inp, conn, weights) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='fixed_pt') + + dense_net[0].run(condition=run_cond, run_cfg=run_cfg) + result_dense = dense_net[2].data.get() + dense_net[0].stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = Sparse(weights=weights_sparse, num_message_bits=8) + sparse_net = create_network(inp, conn, weights_sparse) + sparse_net[0].run(condition=run_cond, run_cfg=run_cfg) + + result_sparse = sparse_net[2].data.get() + sparse_net[0].stop() + + np.testing.assert_array_almost_equal(result_sparse, result_dense) + + def test_weights_get(self): + """Tests the get method on weights.""" + + simtime = 10 + shape = np.random.randint(1, 300, 2).tolist() + weights_init = (np.random.random(shape) - 0.5) * 2 + + # Sparsify + weights_init[np.abs(weights_init) < 0.7] = 0 + weights_init *= 20 + weights_init = weights_init.astype(int) + weights_sparse = csr_matrix(weights_init) + + inp = (np.random.rand(shape[1], simtime) * 10).astype(int) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn = Sparse(weights=weights_sparse) + conn.run(condition=run_cond, run_cfg=run_cfg) + + weights_got = conn.weights.get() + conn.stop() + + self.assertIsInstance(weights_got, csr_matrix) + np.testing.assert_array_equal(weights_got.toarray(), weights_init) + + def test_weights_set(self): + """tests the set method on weights.""" + simtime = 2 + shape = np.random.randint(1, 300, 2).tolist() + weights_init = (np.random.random(shape) - 0.5) * 2 + + # Sparsify + weights_init[np.abs(weights_init) < 0.7] = 0 + weights_init *= 20 + weights_init = weights_init.astype(int) + weights_init_sparse = csr_matrix(weights_init) + + inp = (np.random.rand(shape[1], simtime) * 10).astype(int) + + run_cond = RunSteps(num_steps=1) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn = Sparse(weights=weights_init_sparse) + conn.run(condition=run_cond, run_cfg=run_cfg) + + new_weights_sparse = conn.weights.init.copy() + new_weights_sparse.data = np.random.permutation(new_weights_sparse.data) + + conn.weights.set(new_weights_sparse) + + conn.run(condition=run_cond, run_cfg=run_cfg) + + weights_got_ts_2 = conn.weights.get() + + conn.stop() + + self.assertIsInstance(weights_got_ts_2, csr_matrix) + np.testing.assert_array_equal(weights_got_ts_2.toarray(), + new_weights_sparse.toarray()) + + def test_weights_set_failure(self): + """This tests tries to use set() to change weights but fails as + the number of non-zero weights and their indices change""" + simtime = 2 + shape = (2, 2) + weights_init = np.array([[0, 32], [13, 0]]) + new_weights = np.array([[0, 0], [13, 0]]) + new_weights_2 = np.array([[32, 0], [13, 0]]) + + weights_init_sparse = csr_matrix(weights_init) + new_weights_sparse = csr_matrix(new_weights) + new_weights_sparse_2 = csr_matrix(new_weights_2) + + inp = (np.random.rand(shape[1], simtime) * 10).astype(int) + + run_cond = RunSteps(num_steps=1) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn = Sparse(weights=weights_init_sparse) + sparse_net = create_network(inp, conn, weights_init_sparse) + conn.run(condition=run_cond, run_cfg=run_cfg) + + self.assertRaises(ValueError, conn.weights.set, new_weights_sparse) + self.assertRaises(ValueError, conn.weights.set, new_weights_sparse_2) + conn.stop() + + +class TestLearningSparseProcessModelFloat(unittest.TestCase): + """Tests for LearningSparse class in floating point precision. """ + + def test_consistency_with_learning_dense_random_shape(self): + """Tests if the results of LearningSparse and LearningDense + are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 100, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + weights[weights == 0] = 0.1 + + learning_rule = STDPLoihi( + learning_rate=1, + A_plus=1, + A_minus=-1, + tau_plus=10, + tau_minus=10, + t_epoch=2, + ) + + pre = (np.random.rand(shape[1], simtime) > 0.7).astype(int) + post = (np.random.rand(shape[0], simtime) > 0.7).astype(int) + + conn = LearningDense(weights=weights, + tag_1=weights.copy(), + tag_2=weights.copy(), + learning_rule=learning_rule) + create_learning_network(pre, conn, post) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + weights_got_dense = conn.weights.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + tag_1=weights_sparse.copy(), + tag_2=weights_sparse.copy(), + learning_rule=learning_rule) + create_learning_network(pre, conn, post) + conn.run(condition=run_cond, run_cfg=run_cfg) + + weights_got_sparse = conn.weights.get() + conn.stop() + + np.testing.assert_array_equal(weights_got_dense, + weights_got_sparse.toarray()) + + def test_consistency_with_learning_dense_random_shape_dt(self): + """Tests if the results of LearningSparse and LearningDense + are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 100, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + weights[weights == 0] = 0.1 + + learning_rule = Loihi2FLearningRule(dt="x0 * y1 - y0 * x1", + x1_tau=10, + y1_tau=16, + x1_impulse=16, + y1_impulse=15, + t_epoch=2) + + pre = (np.random.rand(shape[1], simtime) > 0.7).astype(int) + post = (np.random.rand(shape[0], simtime) > 0.7).astype(int) + + conn = LearningDense(weights=weights, + tag_1=weights.copy(), + tag_2=weights.copy(), + learning_rule=learning_rule) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + tags_got_dense = conn.tag_1.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + tag_1=weights_sparse.copy(), + tag_2=weights_sparse.copy(), + learning_rule=learning_rule) + conn.run(condition=run_cond, run_cfg=run_cfg) + + tags_got_sparse = conn.tag_1.get() + conn.stop() + + np.testing.assert_array_equal(tags_got_dense, + tags_got_sparse.toarray()) + + def test_consistency_with_learning_dense_random_shape_dd(self): + """Tests if the results of LearningSparse and LearningDense + are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 100, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + weights[weights == 0] = 0.1 + + learning_rule = Loihi2FLearningRule(dd="x0 * y1 - y0 * x1", + x1_tau=10, + y1_tau=16, + x1_impulse=16, + y1_impulse=15, + t_epoch=2) + + pre = (np.random.rand(shape[1], simtime) > 0.7).astype(int) + post = (np.random.rand(shape[0], simtime) > 0.7).astype(int) + + conn = LearningDense(weights=weights, + tag_1=weights.copy(), + tag_2=weights.copy(), + learning_rule=learning_rule) + dense_net = create_learning_network(pre, conn, post) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + tags_got_dense = conn.tag_2.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + tag_1=weights_sparse.copy(), + tag_2=weights_sparse.copy(), + learning_rule=learning_rule) + sparse_net = create_learning_network(pre, conn, post) + conn.run(condition=run_cond, run_cfg=run_cfg) + + tags_got_sparse = conn.tag_2.get() + conn.stop() + + np.testing.assert_array_equal(tags_got_dense, + tags_got_sparse.toarray()) + + def test_consistency_with_learning_dense_random_shape_graded(self): + """Tests if the results of LearningSparse and LearningDense + are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 100, 2).tolist() + weights = (np.random.random(shape) - 0.5) * 2 + weights[weights == 0] = 0.1 + + learning_rule = STDPLoihi( + learning_rate=1, + A_plus=1, + A_minus=-1, + tau_plus=10, + tau_minus=10, + t_epoch=2, + ) + + pre = (np.random.rand(shape[1], simtime) > 0.7) * 3 + post = (np.random.rand(shape[0], simtime) > 0.7) * 2 + + conn = LearningDense(weights=weights, + tag_1=weights.copy(), + tag_2=weights.copy(), + learning_rule=learning_rule, + num_message_bits=8) + + dense_net = create_learning_network(pre, conn, post, weights=weights) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='floating_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + weights_got_dense = conn.weights.get() + result_dense = dense_net[-1].data.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + tag_1=weights_sparse.copy(), + tag_2=weights_sparse.copy(), + learning_rule=learning_rule, + num_message_bits=8) + + sparse_net = create_learning_network(pre, + conn, + post, + weights=weights_sparse) + conn.run(condition=run_cond, run_cfg=run_cfg) + + weights_got_sparse = conn.weights.get() + result_sparse = sparse_net[-1].data.get() + conn.stop() + + np.testing.assert_array_equal(weights_got_dense, + weights_got_sparse.toarray()) + + np.testing.assert_array_almost_equal(result_sparse, result_dense) + + +class TestLearningSparseProcessModelFixed(unittest.TestCase): + """Tests for LearningSparse class in fixed point precision. """ + + def test_consistency_with_learning_dense_random_shape(self): + """Tests if the results of LearningSparse and LearningDense + are consistent. """ + + simtime = 100 + shape = np.random.randint(1, 100, 2).tolist() + weights = ((np.random.random(shape) - 0.5) * 20).astype(int) + weights[abs(weights) < 2] = 2 + + learning_rule = STDPLoihi( + learning_rate=1, + A_plus=1, + A_minus=-1, + tau_plus=10, + tau_minus=10, + t_epoch=2, + ) + + pre = (np.random.rand(shape[1], simtime) > 0.7).astype(int) + post = (np.random.rand(shape[0], simtime) > 0.7).astype(int) + + conn = LearningDense(weights=weights, + tag_1=weights.copy(), + tag_2=weights.copy(), + learning_rule=learning_rule) + dense_net = create_learning_network(pre, conn, post) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='fixed_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + weights_got_dense = conn.weights.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + tag_1=weights_sparse.copy(), + tag_2=weights_sparse.copy(), + learning_rule=learning_rule) + sparse_net = create_learning_network(pre, conn, post) + conn.run(condition=run_cond, run_cfg=run_cfg) + + weights_got_sparse = conn.weights.get() + conn.stop() + + np.testing.assert_array_equal(weights_got_dense, + weights_got_sparse.toarray()) + + def test_consistency_with_learning_dense_random_shape_dt(self): + """Tests if the results of LearningSparse and LearningDense + are consistent using dt in the learning rule. """ + + simtime = 10 + shape = np.random.randint(1, 100, 2).tolist() + weights = ((np.random.random(shape) - 0.5) * 20).astype(int) + weights[abs(weights) < 2] = 2 + + learning_rule = Loihi2FLearningRule(dt="x0 * y1 - y0 * x1", + x1_tau=10, + y1_tau=16, + x1_impulse=16, + y1_impulse=15, + t_epoch=2) + + pre = (np.random.rand(shape[1], simtime) > 0.7).astype(int) + post = (np.random.rand(shape[0], simtime) > 0.7).astype(int) + + conn = LearningDense(weights=weights, + tag_1=weights.copy(), + tag_2=weights.copy(), + learning_rule=learning_rule) + dense_net = create_learning_network(pre, conn, post) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='fixed_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + tags_got_dense = conn.tag_1.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + tag_1=weights_sparse.copy(), + tag_2=weights_sparse.copy(), + learning_rule=learning_rule) + sparse_net = create_learning_network(pre, conn, post) + conn.run(condition=run_cond, run_cfg=run_cfg) + + tags_got_sparse = conn.tag_1.get() + conn.stop() + + np.testing.assert_array_equal(tags_got_dense, + tags_got_sparse.toarray()) + + def test_consistency_with_learning_dense_random_shape_dd(self): + """Tests if the results of LearningSparse and LearningDense + are consistent using dd in the learning rule. """ + + simtime = 10 + shape = np.random.randint(1, 100, 2).tolist() + weights = ((np.random.random(shape) - 0.5) * 20).astype(int) + weights[abs(weights) < 2] = 2 + + learning_rule = Loihi2FLearningRule(dd="x0 * y1 - y0 * x1", + x1_tau=10, + y1_tau=16, + x1_impulse=16, + y1_impulse=15, + t_epoch=2) + + pre = (np.random.rand(shape[1], simtime) > 0.7).astype(int) + post = (np.random.rand(shape[0], simtime) > 0.7).astype(int) + + conn = LearningDense(weights=weights, + tag_1=weights.copy(), + tag_2=weights.copy(), + learning_rule=learning_rule) + dense_net = create_learning_network(pre, conn, post) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='fixed_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + tags_got_dense = conn.tag_2.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + tag_1=weights_sparse.copy(), + tag_2=weights_sparse.copy(), + learning_rule=learning_rule) + sparse_net = create_learning_network(pre, conn, post) + conn.run(condition=run_cond, run_cfg=run_cfg) + + tags_got_sparse = conn.tag_2.get() + conn.stop() + + np.testing.assert_array_equal(tags_got_dense, + tags_got_sparse.toarray()) + + def test_consistency_with_learning_dense_random_shape_graded(self): + """Tests if the results of LearningSparse and LearningDense + are consistent. """ + + simtime = 10 + shape = np.random.randint(1, 100, 2).tolist() + weights = ((np.random.random(shape) - 0.5) * 20).astype(int) + weights[abs(weights) < 2] = 2 + + learning_rule = STDPLoihi( + learning_rate=1, + A_plus=1, + A_minus=-1, + tau_plus=10, + tau_minus=10, + t_epoch=2, + ) + + pre = (np.random.rand(shape[1], simtime) > 0.7) * 3 + post = (np.random.rand(shape[0], simtime) > 0.7) * 2 + + conn = LearningDense(weights=weights, + tag_1=weights.copy(), + tag_2=weights.copy(), + learning_rule=learning_rule, + num_message_bits=8) + + dense_net = create_learning_network(pre, conn, post, weights=weights) + + run_cond = RunSteps(num_steps=simtime) + run_cfg = Loihi2SimCfg(select_tag='fixed_pt') + + conn.run(condition=run_cond, run_cfg=run_cfg) + weights_got_dense = conn.weights.get() + result_dense = dense_net[-1].data.get() + conn.stop() + + # Run the same network with Sparse + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + tag_1=weights_sparse.copy(), + tag_2=weights_sparse.copy(), + learning_rule=learning_rule, + num_message_bits=8) + + sparse_net = create_learning_network(pre, + conn, + post, + weights=weights_sparse) + conn.run(condition=run_cond, run_cfg=run_cfg) + + weights_got_sparse = conn.weights.get() + result_sparse = sparse_net[-1].data.get() + conn.stop() + + np.testing.assert_array_equal(weights_got_dense, + weights_got_sparse.toarray()) + + np.testing.assert_array_almost_equal(result_sparse, result_dense) + + +class VecSendandRecvProcess(AbstractProcess): + """ + Process of a user-defined shape that sends an arbitrary vector + + Process also listens for incoming connections via InPort a_in. This + allows the test Process to validate that network behavior won't deadlock + in the presence of recurrent connections. + + 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) + self.a_in = InPort(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) + + +@implements(proc=VecSendandRecvProcess, protocol=LoihiProtocol) +@requires(CPU) +@tag('floating_pt') +class PyVecSendModelFloat(PyLoihiProcessModel): + s_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, bool, precision=1) + a_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, float) + vec_to_send: np.ndarray = LavaPyType(np.ndarray, bool, precision=1) + 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 + """ + self.a_in.recv() + + 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=VecSendandRecvProcess, protocol=LoihiProtocol) +@requires(CPU) +@tag('fixed_pt') +class PyVecSendModelFixed(PyLoihiProcessModel): + s_out: PyOutPort = LavaPyType(PyOutPort.VEC_DENSE, bool, precision=1) + a_in: PyInPort = LavaPyType(PyInPort.VEC_DENSE, np.int32, precision=16) + vec_to_send: np.ndarray = LavaPyType(np.ndarray, bool, precision=1) + 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 + """ + self.a_in.recv() + + 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) +@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) +@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 TestDelaySparseProcessModel(unittest.TestCase): + """Tests for ProcessModels of Sparse with synaptic delay.""" + + def test_matrix_weight_delay_expansion(self): + """Tests if the weight-delay matrix is consistent between Dense + and Sparse""" + shape = (5, 4) + weights = np.zeros(shape, dtype=float) + weights[3, 3] = 1 + weights[1, 2] = 3 + weights[3, 1] = 1 + delays = np.zeros(shape, dtype=int) + delays[3, 3] = 1 + delays[1, 2] = 3 + delays[3, 1] = 2 + + weights_sparse = csr_matrix(weights) + delays_sparse = csr_matrix(delays) + wgt_dly_dense = AbstractPyDelayDenseModel.get_delay_wgts_mat(weights, + delays) + wgt_dly_sparse = APDSM.get_delay_wgts_mat(weights_sparse, + delays_sparse) + self.assertTrue(np.all(wgt_dly_sparse == wgt_dly_dense)) + + def test_float_pm_buffer_delay(self): + """Tests floating point Sparse ProcessModel connectivity and temporal + dynamics. All input 'neurons' from the VecSendandRcv fire + once at time t=4, and only 1 connection weight + in the Sparse Process is non-zero. The value of the delay matrix for + this weight is 2. The non-zero connection should have an activation + of 1 at timestep t=7. + """ + shape = (3, 4) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep 4 + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), + num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up Sparse Process with a single non-zero connection weight at + # entry [2, 2] of the connectivity matrix and a delay of 2 at entry + # [2, 2] in the delay matrix. + weights = np.zeros(shape, dtype=float) + weights[2, 2] = 1 + delays = np.zeros(shape, dtype=int) + delays[2, 2] = 2 + weights = csr_matrix(weights) + delays = csr_matrix(delays) + sparse = DelaySparse(weights=weights, delays=delays) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='floating_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # a_out will be equal to 1 at timestep 7, because the dendritic + # accumulators work on inputs from the previous timestep + 2. + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[6, 2] = 1. + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_float_pm_fan_in_delay(self): + """ + Tests floating point Sparse ProcessModel dendritic accumulation + behavior when the fan-in to a receiving neuron is greater than 1 + and synaptic delays are configured. + """ + shape = (3, 4) + num_steps = 10 + # Set up external input to emulate every neuron spiking once on + # timestep 4 + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up a Sparse Process where all input layer neurons project to a + # single output layer neuron with varying delays. + weights = np.zeros(shape, dtype=float) + weights[2, :] = [2, -3, 4, -5] + delays = np.zeros(shape, dtype=int) + delays[2, :] = [1, 2, 2, 4] + weights = csr_matrix(weights) + delays = csr_matrix(delays) + sparse = DelaySparse(weights=weights, delays=delays) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='floating_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # Expected behavior is that a_out corresponding to output + # neuron 3 will be equal to 2 at timestep 6, 1=-3+4 at timestep 7 + # and -5 at timestep 9 + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[5, 2] = 2 + expected_spk_data[6, 2] = 1 + expected_spk_data[8, 2] = -5 + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_float_pm_fan_out_delay(self): + """ + Tests floating point Sparse ProcessModel dendritic accumulation + behavior when the fan-out of a projecting neuron is greater than 1 + and synaptic delays are configured. + """ + shape = (3, 4) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep t=4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up a Sparse Process where a single input layer neuron + # projects to all output layer neurons with a delay of 2 for + # all synapses. + weights = np.zeros(shape, dtype=float) + weights[:, 2] = [3, 4, 5] + delays = np.zeros(shape, dtype=int) + delays = 2 + weights = csr_matrix(weights) + sparse = DelaySparse(weights=weights, delays=delays) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='floating_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # Expected behavior is that a_out corresponding to output + # neurons 1-3 will be equal to 3, 4, and 5, respectively, at + # timestep 7. + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[6, :] = [3, 4, 5] + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_float_pm_fan_out_delay_2(self): + """ + Tests floating point Sparse ProcessModel dendritic accumulation + behavior when the fan-out of a projecting neuron is greater than 1 + and synaptic delays are configured. + """ + shape = (3, 4) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep t=4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up a Sparse Process where a single input layer neuron projects + # to all output layer neurons with varying delays. + weights = np.zeros(shape, dtype=float) + weights[:, 2] = [3, 4, 5] + delays = np.zeros(shape, dtype=int) + delays[:, 2] = [0, 1, 2] + weights = csr_matrix(weights) + delays = csr_matrix(delays) + sparse = DelaySparse(weights=weights, delays=delays) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='floating_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # Expected behavior is that a_out corresponding to output + # neurons 1-3 will be equal to 3, 4, and 5, respectively, at + # timestep 5, 6 and 7, respectively. + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[4, 0] = 3 + expected_spk_data[5, 1] = 4 + expected_spk_data[6, 2] = 5 + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_float_pm_recurrence_delays(self): + """ + Tests that floating Sparse ProcessModel has non-blocking dynamics + for recurrent connectivity architectures and synaptic delays are + configured. + """ + shape = (3, 3) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep 4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(True, (num_steps,)) + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up Sparse Process with fully connected recurrent connectivity + # architecture + weights = np.ones(shape, dtype=float) + delays = 2 + weights = csr_matrix(weights) + sparse = DelaySparse(weights=weights, delays=delays) + # Receive neuron spikes + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(sps.a_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='floating_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + sparse.stop() + + def test_bitacc_pm_fan_out_excitatory_delay(self): + """ + Tests fixed-point Sparse ProcessModel dendritic accumulation + behavior when the fan-out of a projecting neuron is greater than 1 + and all connections are excitatory (sign_mode = 2) and synaptic + delays are configured. + """ + shape = (3, 4) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep 4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up Sparse Process in which a single input neuron projects + # to all output neurons. + weights = np.zeros(shape, dtype=float) + weights[:, 2] = [0.5, 300, 40] + delays = np.zeros(shape, dtype=int) + delays[:, 2] = [0, 1, 2] + weights = csr_matrix(weights) + delays = csr_matrix(delays) + sparse = DelaySparse(weights=weights, + delays=delays, + sign_mode=SignMode.EXCITATORY) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='fixed_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # Expected behavior is that a_out corresponding to output + # neurons 1-3 will be equal to 0, 255, and 40, respectively, + # at timestep 5, 6 and 7, because a_out can only have integer values + # between 0 and 255 and we have a delay of 0, 1, 2 on the synapses, + # respectively. + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[4, 0] = 0 + expected_spk_data[5, 1] = 255 + expected_spk_data[6, 2] = 40 + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_bitacc_pm_fan_out_mixed_sign_delay(self): + """ + Tests fixed-point Sparse ProcessModel dendritic accumulation + behavior when the fan-out of a projecting neuron is greater than 1 + and connections are both excitatory and inhibitory (sign_mode = 1). + When using mixed sign weights and full 8 bit weight precision, + a_out can take even values from -256 to 254. A delay of 2 for all + synapses is configured. + """ + shape = (3, 4) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep 4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up Sparse Process in which a single input neuron projects to + # all output neurons with both excitatory and inhibitory weights. + weights = np.zeros(shape, dtype=float) + weights[:, 2] = [300, -300, 39] + delays = np.zeros(shape, dtype=int) + delays = 2 + weights = csr_matrix(weights) + sparse = DelaySparse(weights=weights, + delays=delays, + sign_mode=SignMode.MIXED) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='fixed_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # Expected behavior is that a_out corresponding to output + # neurons 1-3 will be equal to 254, -256, and 38, respectively, + # at timestep 7, because a_out can only have even values between + # -256 and 254 and a delay of 2 is configured. + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[6, :] = [254, -256, 38] + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_bitacc_pm_fan_out_weight_exp_delay(self): + """ + Tests fixed-point Sparse ProcessModel dendritic accumulation + behavior when the fan-out of a projecting neuron is greater than 1 + , connections are both excitatory and inhibitory (sign_mode = 1), + and weight_exp = 1. + When using mixed sign weights, full 8 bit weight precision, + and weight_exp = 1, a_out can take even values from -512 to 508. + As a result of setting weight_exp = 1, the expected a_out result + is 2x that of the previous unit test. A delay of 0, 1, 2 is + configured for respective synapses. + """ + + shape = (3, 4) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep 4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up Sparse Process in which all input neurons project to a + # single output neuron with mixed sign connection weights. + weights = np.zeros(shape, dtype=float) + weights[:, 2] = [300, -300, 39] + delays = np.zeros(shape, dtype=int) + delays[:, 2] = [0, 1, 2] + weights = csr_matrix(weights) + delays = csr_matrix(delays) + # Set weight_exp = 1. This affects weight scaling. + sparse = DelaySparse(weights=weights, weight_exp=1, delays=delays) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='fixed_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # Expected behavior is that a_out corresponding to output + # neurons 1-3 will be equal to 508, -512, and 76, respectively, + # at timestep 5, 6, and 7, respectively, because a_out can only + # have values between -512 and 508 such that a_out % 4 = 0. + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[4, 0] = 508 + expected_spk_data[5, 1] = -512 + expected_spk_data[6, 2] = 76 + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_bitacc_pm_fan_out_weight_precision_delay(self): + """ + Tests fixed-point Sparse ProcessModel dendritic accumulation + behavior when the fan-out of a projecting neuron is greater than 1 + , connections are both excitatory and inhibitory (sign_mode = 1), + and num_weight_bits = 7. + When using mixed sign weights and 7 bit weight precision, + a_out can take values from -256 to 252 such that a_out % 4 = 0. + All synapses have a delay of 2 configured. + """ + + shape = (3, 4) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep 4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up Sparse Process in which all input neurons project to a + # single output neuron with mixed sign connection weights. + weights = np.zeros(shape, dtype=float) + weights[:, 2] = [300, -300, 39] + delays = np.zeros(shape, dtype=int) + delays = 2 + weights = csr_matrix(weights) + # Set num_weight_bits = 7. This affects weight scaling. + sparse = DelaySparse(weights=weights, + num_weight_bits=7, + delays=delays) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='fixed_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # Expected behavior is that a_out corresponding to output + # neurons 1-3 will be equal to 252, -256, and 36, respectively, + # at timestep 7, because a_out can only have values between -256 + # and 252 such that a_out % 4 = 0. + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[6, :] = [252, -256, 36] + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_bitacc_pm_fan_in_mixed_sign_delay(self): + """ + Tests fixed-point Sparse ProcessModel dendritic accumulation + behavior when the fan-in of a receiving neuron is greater than 1 + and connections are both excitatory and inhibitory (sign_mode = 1). + When using mixed sign weights and full 8 bit weight precision, + a_out can take even values from -256 to 254. All synapses have a + delay of 2 configured. + """ + shape = (3, 4) + num_steps = 8 + # Set up external input to emulate every neuron spiking once on + # timestep 4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(False, (num_steps,)) + send_at_times[3] = True + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up Sparse Process in which all input layer neurons project to + # a single output layer neuron with both excitatory and inhibitory + # weights. + weights = np.zeros(shape, dtype=float) + weights[2, :] = [300, -300, 39, -0.4] + delays = np.zeros(shape, dtype=int) + delays = 2 + weights = csr_matrix(weights) + sparse = DelaySparse(weights=weights, + sign_mode=SignMode.MIXED, + delays=delays) + # Receive neuron spikes + spr = VecRecvProcess(shape=(num_steps, shape[0])) + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(spr.s_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='fixed_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + # Gather spike data and stop + spk_data_through_run = spr.spk_data.get() + sparse.stop() + # Gold standard for the test + # Expected behavior is that a_out corresponding to output + # neuron 3 will be equal to 36=254-256+38-0 at timestep 7, because + # weights can only have even values between -256 and 254. + expected_spk_data = np.zeros((num_steps, shape[0])) + expected_spk_data[6, 2] = 36 + self.assertTrue(np.all(expected_spk_data == spk_data_through_run)) + + def test_bitacc_pm_recurrence_delay(self): + """ + Tests that bit accurate Sparse ProcessModel has non-blocking + dynamics for recurrent connectivity architectures. All + synapses have a delay of 2 configured. + """ + shape = (3, 3) + num_steps = 6 + # Set up external input to emulate every neuron spiking once on + # timestep 4. + vec_to_send = np.ones((shape[1],), dtype=float) + send_at_times = np.repeat(True, (num_steps,)) + sps = VecSendandRecvProcess(shape=(shape[1],), num_steps=num_steps, + vec_to_send=vec_to_send, + send_at_times=send_at_times) + # Set up Sparse Process with fully connected recurrent connectivity + # architecture. + weights = np.ones(shape, dtype=float) + delays = 2 + weights = csr_matrix(weights) + sparse = DelaySparse(weights=weights, delays=delays) + # Receive neuron spikes + sps.s_out.connect(sparse.s_in) + sparse.a_out.connect(sps.a_in) + # Configure execution and run + rcnd = RunSteps(num_steps=num_steps) + rcfg = Loihi2SimCfg(select_tag='floating_pt') + sparse.run(condition=rcnd, run_cfg=rcfg) + sparse.stop() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/lava/proc/sparse/test_process.py b/tests/lava/proc/sparse/test_process.py new file mode 100644 index 000000000..e26c22ae8 --- /dev/null +++ b/tests/lava/proc/sparse/test_process.py @@ -0,0 +1,134 @@ +# 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, spmatrix + +from lava.utils.sparse import find +from lava.proc.sparse.process import Sparse, LearningSparse, DelaySparse +from lava.proc.learning_rules.stdp_learning_rule import STDPLoihi + + +class TestFunctions(unittest.TestCase): + """Test helper function for Sparse""" + + def test_find_with_explicit_zeros(self): + + mat = np.random.randint(-10, 10, (3, 5)) + spmat = csr_matrix(mat) + spmat.data[0] = 0 + + _, _, vals = find(spmat, explicit_zeros=True) + + self.assertTrue(np.all(spmat.data in vals)) + + +class TestSparseProcess(unittest.TestCase): + """Tests for Sparse class""" + + def test_init(self): + """Tests instantiation of Sparse""" + shape = (100, 200) + weights = np.random.random(shape) + + # Sparsify + weights[weights < 0.7] = 0 + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = Sparse(weights=weights_sparse) + + self.assertIsInstance(conn.weights.init, spmatrix) + np.testing.assert_array_equal(conn.weights.init.toarray(), weights) + + +class TestLearningSparseProcess(unittest.TestCase): + """Tests for LearningSparse class""" + + def test_init(self): + """Tests instantiation of LearningSparse""" + + learning_rule = STDPLoihi( + learning_rate=1, + A_plus=1, + A_minus=-2, + tau_plus=10, + tau_minus=10, + t_epoch=2, + ) + + shape = (100, 200) + weights = np.random.random(shape) + + # Sparsify + weights[weights < 0.7] = 0 + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + + conn = LearningSparse(weights=weights_sparse, + learning_rule=learning_rule) + + self.assertIsInstance(conn.weights.init, spmatrix) + np.testing.assert_array_equal(conn.weights.init.toarray(), weights) + + +class TestDelaySparseProcess(unittest.TestCase): + """Tests for Sparse class""" + + def test_init(self): + """Tests instantiation of Sparse""" + shape = (100, 200) + weights = np.random.random(shape) + delays = np.random.randint(0, 3, shape) + + # Sparsify + weights[weights < 0.7] = 0 + delays[weights < 0.7] = 0 + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + delays_sparse = csr_matrix(delays) + + conn = DelaySparse(weights=weights_sparse, delays=delays_sparse) + + self.assertIsInstance(conn.weights.init, spmatrix) + np.testing.assert_array_equal(conn.weights.init.toarray(), weights) + + def test_validate_shapes(self): + """Tests if the weights and delay have correct shape""" + + shape = (3, 2) + weights = np.random.random(shape) + + shape = (2, 3) + delays = np.random.randint(0, 3, shape) + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + delays_sparse = csr_matrix(delays) + + np.testing.assert_raises(ValueError, + DelaySparse, + weights=weights_sparse, + delays=delays_sparse) + + def test_validate_nonzero_delays(self): + """Tests if the weights and delay have correct shape""" + + shape = (3, 2) + weights = np.random.random(shape) + delays = np.random.randint(0, 3, shape) + delays[0] = -1 + + # Convert to spmatrix + weights_sparse = csr_matrix(weights) + delays_sparse = csr_matrix(delays) + + np.testing.assert_raises(ValueError, + DelaySparse, + weights=weights_sparse, + delays=delays_sparse) diff --git a/tests/lava/proc/spiker/test_models.py b/tests/lava/proc/spiker/test_models.py index 147dbf269..9d92bc328 100644 --- a/tests/lava/proc/spiker/test_models.py +++ b/tests/lava/proc/spiker/test_models.py @@ -17,7 +17,7 @@ def test_single_spiker_counter(self): "Tests a single spiker for multiple time steps." spiker = Spiker(shape=(1,), period=5) counter = [] - for timestep in range(20): + for _ in range(20): spiker.run(condition=RunSteps(num_steps=1), run_cfg=Loihi2SimCfg()) counter.append(spiker.counter.get()[0]) @@ -31,7 +31,7 @@ def test_multiple_spikers_counter(self): spiker = Spiker(shape=(2,), period=5) counter1 = [] counter2 = [] - for timestep in range(20): + for _ in range(20): spiker.run(condition=RunSteps(num_steps=1), run_cfg=Loihi2SimCfg()) counter1.append(spiker.counter.get()[0]) diff --git a/tests/lava/test_utils/utils.py b/tests/lava/test_utils/utils.py index e1ec81397..27eb9f11d 100644 --- a/tests/lava/test_utils/utils.py +++ b/tests/lava/test_utils/utils.py @@ -3,13 +3,13 @@ # See: https://spdx.org/licenses/ import os -import subprocess +import subprocess # noqa S404 import importlib class Utils: - """Utility Class containing testing helper - code that can be reused between tests + """Utility Class containing testing helper code that can be reused + between tests. """ @staticmethod @@ -26,7 +26,7 @@ def get_bool_env_setting(env_var: str): @staticmethod def is_loihi2_available() -> bool: - """"Checks if Loihi2 is available and can be accessed.""" + """Checks if Loihi 2 is available and can be accessed.""" is_loihi2 = False is_slurm = False @@ -37,7 +37,7 @@ def is_loihi2_available() -> bool: is_slurm = True # Check if Loihi2 is available - sinfo = subprocess.run("sinfo", # noqa: S603, S607 + sinfo = subprocess.run("sinfo", # nosec # noqa: S603, S607 stdout=subprocess.PIPE).stdout.decode( 'utf-8') for line in sinfo.split("\n"): diff --git a/tests/lava/tutorials/test_tutorials.py b/tests/lava/tutorials/test_tutorials.py index 1ca31679c..569585a8e 100644 --- a/tests/lava/tutorials/test_tutorials.py +++ b/tests/lava/tutorials/test_tutorials.py @@ -5,7 +5,7 @@ import glob import os import platform -import subprocess # noqa: S404 +import subprocess # noqa S404 import sys import tempfile import typing as ty @@ -115,7 +115,8 @@ def _convert_and_execute_notebook( fout.name[0:-3], notebook, ] - subprocess.check_call(args, env=env) # noqa: S603 + subprocess.check_call(args, env=env) # nosec # noqa: S603 + fout.seek(0) return subprocess.run(["ipython", "-c", fout.read()], # noqa # nosec env=env) # noqa # nosec diff --git a/tests/lava/utils/test_plots.py b/tests/lava/utils/test_plots.py index 04765af1f..4219e5297 100644 --- a/tests/lava/utils/test_plots.py +++ b/tests/lava/utils/test_plots.py @@ -30,7 +30,7 @@ def test_bad_spikes_shape(self) -> None: with self.assertRaises(ValueError) as cm: raster_plot(spikes) - self.assertEquals( + self.assertEqual( str(cm.exception), "Parameter must have exactly two dimensions and " "they must be non-empty.", @@ -43,19 +43,19 @@ def test_non_binary_values(self) -> None: with self.assertRaises(ValueError) as cm: raster_plot(spikes) - self.assertEquals(str(cm.exception), error_msg) + self.assertEqual(str(cm.exception), error_msg) spikes = np.array([[0, -1], [0, 0]]) with self.assertRaises(ValueError) as cm: raster_plot(spikes) - self.assertEquals(str(cm.exception), error_msg) + self.assertEqual(str(cm.exception), error_msg) def test_bad_stride(self) -> None: with self.assertRaises(ValueError) as cm: raster_plot(self.spikes, stride=11) - self.assertEquals( + self.assertEqual( str(cm.exception), "Stride must not be greater than the number of neurons.", ) @@ -64,7 +64,7 @@ def test_both_fig_and_figsize_provided(self) -> None: with self.assertRaises(ValueError) as cm: raster_plot(self.spikes, fig=plt.figure(), figsize=(10, 10)) - self.assertEquals( + self.assertEqual( str(cm.exception), "Must use at most one of the following: fig, figsize.", ) diff --git a/tutorials/in_depth/three_factor_learning/utils.py b/tutorials/in_depth/three_factor_learning/utils.py index 230cadfc6..7320fe94d 100644 --- a/tutorials/in_depth/three_factor_learning/utils.py +++ b/tutorials/in_depth/three_factor_learning/utils.py @@ -3,21 +3,14 @@ # See: https://spdx.org/licenses/ import matplotlib.pyplot as plt -import typing as ty import numpy as np -from lava.proc.lif.process import LIF, AbstractLIF, LogConfig, LearningLIF -from lava.proc.io.source import RingBuffer -from lava.proc.dense.process import LearningDense, Dense -from lava.magma.core.process.neuron import LearningNeuronProcess -from lava.proc.learning_rules.r_stdp_learning_rule import RewardModulatedSTDP -from lava.magma.core.process.variable import Var -from lava.magma.core.process.ports.ports import InPort, OutPort +from lava.proc.lif.process import LearningLIF from lava.magma.core.model.py.neuron import ( LearningNeuronModelFloat, LearningNeuronModelFixed ) 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.ports import 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 @@ -188,8 +181,7 @@ def run_spk(self) -> None: self.s_out_y3.send(self.y3) -def generate_post_spikes(pre_spike_times, - num_steps, spike_prob_post): +def generate_post_spikes(pre_spike_times, num_steps, spike_prob_post): """generates specific post synaptic spikes to demonstrate potentiation and depression. """ @@ -211,16 +203,17 @@ def generate_post_spikes(pre_spike_times, return spike_raster_post + def plot_spikes(spikes, figsize, legend, colors, title, num_steps): offsets = list(range(1, len(spikes) + 1)) num_x_ticks = np.arange(0, num_steps+1, 25) plt.figure(figsize=figsize) - spikes_plot = plt.eventplot(positions=spikes, - lineoffsets=offsets, - linelength=0.9, - colors=colors) + plt.eventplot(positions=spikes, + lineoffsets=offsets, + linelength=0.9, + colors=colors) plt.title(title) plt.xlabel("Time steps") @@ -233,9 +226,9 @@ def plot_spikes(spikes, figsize, legend, colors, title, num_steps): plt.yticks(ticks=offsets, labels=legend) - plt.show() + def plot_time_series(time, time_series, ylabel, title, figsize, color): plt.figure(figsize=figsize) plt.step(time, time_series, color=color) @@ -250,7 +243,10 @@ def plot_time_series(time, time_series, ylabel, title, figsize, color): plt.show() -def plot_time_series_subplots(time, time_series_y1, time_series_y2, ylabel, title, figsize, color, legend, leg_loc="upper left"): + +def plot_time_series_subplots(time, time_series_y1, time_series_y2, ylabel, + title, figsize, color, legend, + leg_loc="upper left"): plt.figure(figsize=figsize) plt.step(time, time_series_y1, label=legend[0], color=color[0]) @@ -268,7 +264,9 @@ def plot_time_series_subplots(time, time_series_y1, time_series_y2, ylabel, titl plt.show() -def plot_spikes_time_series(time, time_series, spikes, figsize, legend, colors, title, num_steps): + +def plot_spikes_time_series(time, time_series, spikes, figsize, legend, + colors, title, num_steps): offsets = list(range(1, len(spikes) + 1)) num_x_ticks = np.arange(0, num_steps+1, 25)