├── .python-version ├── .gitignore ├── analysis ├── requirements.txt ├── random.png ├── README.md ├── uniform.md └── generate_plot.py ├── tests ├── test_qrandom.py ├── test_numpy_support.py ├── data │ └── fetch_data.py ├── conftest.py ├── test_generator.py ├── test_cli.py └── test_api.py ├── .github └── workflows │ ├── publish.yml │ └── tests.yml ├── src └── qrandom │ ├── numpy.py │ ├── _cli.py │ ├── _generator.py │ ├── __init__.py │ └── _api.py ├── LICENSE ├── pyproject.toml ├── README.md └── uv.lock /.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | dist/ 3 | *.egg-info/ 4 | -------------------------------------------------------------------------------- /analysis/requirements.txt: -------------------------------------------------------------------------------- 1 | scipy 2 | matplotlib 3 | quantum-random 4 | -------------------------------------------------------------------------------- /analysis/random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbalian/quantum-random/HEAD/analysis/random.png -------------------------------------------------------------------------------- /tests/test_qrandom.py: -------------------------------------------------------------------------------- 1 | import qrandom 2 | 3 | 4 | def test_all_is_subset_of_everything_in_module(): 5 | assert set(qrandom.__all__).issubset(set(dir(qrandom))) 6 | -------------------------------------------------------------------------------- /analysis/README.md: -------------------------------------------------------------------------------- 1 | # Analysis 2 | 3 | To run the analysis, first install the requirements (includes `quantum-random`): 4 | 5 | ```bash 6 | pip install -r requirements.txt 7 | ``` 8 | 9 | Then run the script to generate the plot in `uniform.md`: 10 | 11 | ```bash 12 | python generate_plot.py 13 | ``` 14 | 15 | The output is written to `random.png`. 16 | -------------------------------------------------------------------------------- /tests/test_numpy_support.py: -------------------------------------------------------------------------------- 1 | from qrandom import numpy 2 | 3 | 4 | def test_numpy_support(mocker, test_responses): 5 | mocker.patch( 6 | "qrandom._api.Client.fetch_hex_raw", 7 | side_effect=test_responses, 8 | ) 9 | numbers = numpy.quantum_rng().random((3, 3)) 10 | assert ((numbers >= 0.0) & (numbers < 1.0)).all() 11 | return 12 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | release: 10 | permissions: 11 | id-token: write 12 | name: Release 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout repo 16 | uses: actions/checkout@v4 17 | - name: Install uv 18 | uses: astral-sh/setup-uv@v3 19 | with: 20 | version: "0.5.4" 21 | - name: Build 22 | run: uv build 23 | - name: Publish 24 | run: uv publish 25 | -------------------------------------------------------------------------------- /src/qrandom/numpy.py: -------------------------------------------------------------------------------- 1 | """Adds numpy support to qrandom.""" 2 | 3 | from typing import Any 4 | 5 | import randomgen 6 | from numpy import random as numpy_random 7 | 8 | from . import _generator 9 | 10 | 11 | class _ANUQRNG(_generator.QuantumRandom): 12 | def __init__(self, batch_size: int = 1024) -> None: 13 | super().__init__(batch_size=batch_size) 14 | return 15 | 16 | def random_raw(self, voidp: Any) -> int: 17 | return self._get_rand_int64() 18 | 19 | 20 | def quantum_rng(batch_size: int = 1024): 21 | """Constructs a new Generator with a quantum BitGenerator. 22 | 23 | batch_size is the number of ANU random numbers fetched and cached 24 | per API call (default is maximum allowed: 1024). 25 | 26 | """ 27 | qrn = _ANUQRNG(batch_size=batch_size) 28 | return numpy_random.Generator(randomgen.UserBitGenerator(qrn.random_raw)) # type: ignore[arg-type] # noqa: E501 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2024 Seto Balian 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19 | USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /analysis/uniform.md: -------------------------------------------------------------------------------- 1 | # Visualise and test if the quantum randoms are uniformly distributed in [0.0, 1) 2 | 3 | Calling `qrandom.random()` 10,000 times, and comparing it to `random.random()`: 4 | 5 | ![Random](./random.png) 6 | 7 | The [Kolmogorov–Smirnov statistics][kstest] with the reference distribution 8 | `scipy.uniform` gives the following results. 9 | 10 | | Trial | Quantum statistic | Quantum p-value | Std. statistic | Std. p-value | 11 | | ----- | ----------------- | --------------- | ---------------| -------------| 12 | | 1 | 0.01 | 0.2 | 0.005 | 0.9 | 13 | | 2 | 0.007 | 0.7 | 0.005 | 1.0 | 14 | | 3 | 0.006 | 0.9 | 0.008 | 0.6 | 15 | | 4 | 0.01 | 0.3 | 0.008 | 0.5 | 16 | 17 | Each trial is a different run of [`scipy.stats.kstest`][scipy-kstest] with 18 | 10,000 numbers. The plot shows the numbers for the last trial. 19 | 20 | [kstest]: https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test 21 | [scipy-kstest]: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kstest.html 22 | -------------------------------------------------------------------------------- /tests/data/fetch_data.py: -------------------------------------------------------------------------------- 1 | import json 2 | import pathlib 3 | 4 | import click 5 | 6 | from qrandom import _api 7 | 8 | 9 | @click.command() 10 | @click.option( 11 | "--num-hits", 12 | "-n", 13 | type=int, 14 | default=10, 15 | show_default=True, 16 | help="Number of API calls.", 17 | ) 18 | @click.option( 19 | "--output-directory", 20 | "-o", 21 | type=click.Path( 22 | exists=True, 23 | file_okay=False, 24 | resolve_path=True, 25 | path_type=pathlib.Path, 26 | ), 27 | default=pathlib.Path("."), 28 | help="Output directory.", 29 | show_default=True, 30 | ) 31 | def main(num_hits, output_directory) -> None: 32 | """Write a JSON file of responses from the ANU API for testing purposes.""" 33 | 34 | output_path = output_directory / "responses.json" 35 | if output_path.exists(): 36 | click.confirm( 37 | f"Would you like to overwrite {output_path}?", 38 | abort=True, 39 | ) 40 | 41 | key = _api.find_api_key() 42 | client = _api.Client(key) 43 | 44 | click.echo("Fetching data ...") 45 | with click.progressbar(range(num_hits)) as bar: 46 | responses = [client.fetch_hex_raw() for _ in bar] 47 | click.echo("Writing responses ...") 48 | with open(pathlib.Path(output_path), "w") as f: 49 | json.dump(responses, f) 50 | click.echo(f"Wrote responses to {output_path} .") 51 | 52 | return 53 | 54 | 55 | if __name__ == "__main__": 56 | main() 57 | -------------------------------------------------------------------------------- /analysis/generate_plot.py: -------------------------------------------------------------------------------- 1 | import random 2 | from typing import List, Tuple 3 | 4 | import matplotlib.pyplot as plt 5 | from scipy import stats 6 | 7 | import qrandom 8 | 9 | DataType = Tuple[Tuple[List[float], str], Tuple[List[float], str]] 10 | 11 | 12 | def generate_data() -> DataType: 13 | numbers = [qrandom.random() for _ in range(10000)] 14 | py_numbers = [random.random() for _ in range(10000)] 15 | return (numbers, "Quantum random"), (py_numbers, "Python pseudo-random") 16 | 17 | 18 | def plot(data: DataType) -> None: 19 | quantum, python = data 20 | numbers, quantum_title = quantum 21 | py_numbers, python_title = python 22 | 23 | plt.figure(figsize=(8, 3)) 24 | plt.subplot(1, 2, 1) 25 | plt.hist(numbers, edgecolor="black") 26 | plt.title(quantum_title) 27 | plt.subplot(1, 2, 2) 28 | plt.hist(py_numbers, edgecolor="black") 29 | plt.title(python_title) 30 | plt.tight_layout() 31 | plt.savefig("random.png", dpi=120, bbox_inches="tight") 32 | return 33 | 34 | 35 | def kstest(data: DataType) -> None: 36 | quantum, python = data 37 | numbers, quantum_title = quantum 38 | py_numbers, python_title = python 39 | 40 | print(quantum_title, stats.kstest(numbers, "uniform")) 41 | print(python_title, stats.kstest(py_numbers, "uniform")) 42 | return 43 | 44 | 45 | def main() -> None: 46 | data = generate_data() 47 | plot(data) 48 | kstest(data) 49 | return 50 | 51 | 52 | if __name__ == "__main__": 53 | main() 54 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: push 4 | 5 | jobs: 6 | test: 7 | name: Tests and type checks 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-latest, macos-latest, windows-latest] 12 | python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] 13 | defaults: 14 | run: 15 | shell: bash 16 | steps: 17 | - name: Checkout repo 18 | uses: actions/checkout@v4 19 | - name: Install uv 20 | uses: astral-sh/setup-uv@v3 21 | with: 22 | version: "0.5.4" 23 | - name: Set up Python ${{ matrix.python-version }} 24 | run: uv python install ${{ matrix.python-version }} 25 | - name: Install the project 26 | run: uv sync --all-extras --dev 27 | - name: Run pytest 28 | run: QRANDOM_API_KEY=key uv run pytest 29 | - name: Run mypy 30 | run: uv run mypy --install-types --non-interactive . 31 | 32 | lint: 33 | name: Lint 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Checkout repo 37 | uses: actions/checkout@v4 38 | - name: Install uv 39 | uses: astral-sh/setup-uv@v3 40 | with: 41 | version: "0.5.4" 42 | - name: Set up Python 43 | run: uv python install 44 | - name: Install the project 45 | run: uv sync --all-extras --dev 46 | - name: Run black 47 | run: uv run black --check . 48 | - name: Run isort 49 | run: uv run isort --check . 50 | - name: Run flake8 51 | run: uv run flake8 --extend-exclude .venv 52 | -------------------------------------------------------------------------------- /src/qrandom/_cli.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | import os 3 | import pathlib 4 | import sys 5 | 6 | import click 7 | import xdg 8 | 9 | 10 | @click.command() 11 | def main() -> None: 12 | """This utility will help you set the API key for the qrandom package. 13 | 14 | You can get a key from https://quantumnumbers.anu.edu.au/pricing. 15 | 16 | """ 17 | 18 | default_config_dir = xdg.xdg_config_home() / "qrandom" 19 | 20 | config_dir = click.prompt( 21 | "Where would you like to store the key?", 22 | type=pathlib.Path, 23 | default=default_config_dir, 24 | ) 25 | config_dir = config_dir.expanduser().resolve() 26 | if config_dir.exists() and config_dir.is_file(): 27 | click.echo(f"{config_dir} is not a directory.", err=True) 28 | sys.exit(1) 29 | config_path = config_dir / "qrandom.ini" 30 | if config_path.exists(): 31 | click.confirm( 32 | f"Would you like to overwrite {config_path}?", 33 | abort=True, 34 | ) 35 | 36 | config = configparser.ConfigParser() 37 | config.add_section("default") 38 | 39 | api_key = click.prompt( 40 | "Enter your API key", 41 | type=str, 42 | ) 43 | 44 | os.makedirs(config_dir, exist_ok=True) 45 | config["default"]["key"] = api_key 46 | with open(config_path, "w") as f: 47 | config.write(f) 48 | click.echo(f"Stored API key in {config_path}.") 49 | if config_dir != default_config_dir: 50 | click.echo( 51 | "Since you did not write to the default path, " 52 | f"do not forget to set QRANDOM_CONFIG_DIR to {config_dir}." 53 | ) 54 | return 55 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "quantum-random" 3 | version = "1.4.2" 4 | description = "Quantum random numbers" 5 | readme = "README.md" 6 | license = {text = "MIT License"} 7 | authors = [ 8 | { name = "Seto Balian", email = "seto.balian@gmail.com" } 9 | ] 10 | maintainers = [ 11 | { name = "Seto Balian", email = "seto.balian@gmail.com" } 12 | ] 13 | keywords = ["quantum", "random", "statistics"] 14 | classifiers = [ 15 | "Intended Audience :: Science/Research", 16 | "Intended Audience :: Developers", 17 | "Programming Language :: Python", 18 | "Programming Language :: Python :: 3", 19 | "Topic :: Software Development", 20 | "Topic :: Scientific/Engineering", 21 | "Typing :: Typed", 22 | "Operating System :: Microsoft :: Windows", 23 | "Operating System :: Unix", 24 | "Operating System :: MacOS", 25 | "License :: OSI Approved :: MIT License", 26 | ] 27 | requires-python = ">=3.9" 28 | dependencies = [ 29 | "click>=8.1.7", 30 | "requests>=2.32.3", 31 | "xdg>=6.0.0", 32 | ] 33 | 34 | [project.optional-dependencies] 35 | numpy = [ 36 | "numpy>=2.0.2", 37 | "randomgen>=2.1.1", 38 | ] 39 | 40 | [dependency-groups] 41 | dev = [ 42 | "pytest-mock>=3.14.0", 43 | "pytest>=8.3.3", 44 | "responses>=0.25.3", 45 | "mypy>=1.13.0", 46 | "flake8>=7.1.1", 47 | "isort>=5.13.2", 48 | "black>=24.10.0", 49 | "pip>=24.3.1", 50 | ] 51 | 52 | [project.scripts] 53 | qrandom-init = "qrandom._cli:main" 54 | 55 | [project.urls] 56 | Homepage = "https://github.com/sbalian/quantum-random" 57 | Repository = "https://github.com/sbalian/quantum-random" 58 | 59 | [build-system] 60 | requires = ["hatchling"] 61 | build-backend = "hatchling.build" 62 | 63 | [tool.hatch.build.targets.wheel] 64 | packages = ["src/qrandom"] 65 | 66 | [tool.pytest.ini_options] 67 | addopts = "--verbose" 68 | testpaths = "tests" 69 | 70 | [tool.mypy] 71 | ignore_missing_imports = true 72 | 73 | [tool.black] 74 | line-length = 79 75 | 76 | [tool.isort] 77 | profile = "black" 78 | line_length = 79 79 | known_first_party = ["qrandom"] 80 | -------------------------------------------------------------------------------- /src/qrandom/_generator.py: -------------------------------------------------------------------------------- 1 | import random as pyrandom 2 | import warnings 3 | from typing import List, NoReturn 4 | 5 | from . import _api 6 | 7 | 8 | class QuantumRandom(pyrandom.Random): 9 | """Quantum random number generator.""" 10 | 11 | def __init__(self, batch_size: int = 1024): 12 | """Initialises an instance of QuantumRandom. 13 | 14 | batch_size is the number of ANU random numbers fetched and cached 15 | per API call (default is maximum allowed: 1024). 16 | 17 | """ 18 | with warnings.catch_warnings(): 19 | warnings.simplefilter("ignore", category=UserWarning) 20 | super().__init__() 21 | self._rand_int64: List[int] = [] 22 | if not (0 < batch_size <= 1024): 23 | raise ValueError("batch_size must be > 0 and up to 1024") 24 | self._api_client = _api.Client( 25 | _api.find_api_key(), batch_size=batch_size 26 | ) 27 | return 28 | 29 | def fill(self, n: int = 1): 30 | """Fills the generator with n batches of 64-bit ints. 31 | 32 | The batch size is set during initialisation. 33 | 34 | """ 35 | for _ in range(n): 36 | self._rand_int64.extend(self._api_client.fetch_int64()) 37 | return 38 | 39 | def _get_rand_int64(self) -> int: 40 | if not self._rand_int64: 41 | self.fill() 42 | return self._rand_int64.pop() 43 | 44 | def random(self) -> float: 45 | """Gets the next quantum random number in the range [0.0, 1.0).""" 46 | return self._get_rand_int64() / (2**64) 47 | 48 | def seed(self, *args, **kwds) -> None: 49 | """Method is ignored. There is no seed for the quantum vacuum. 50 | 51 | Raises RuntimeError if docstring for seed does not exist. 52 | 53 | """ 54 | if self.seed.__doc__ is None: 55 | raise RuntimeError("docstring for seed must exist") 56 | warnings.warn(self.seed.__doc__) 57 | return 58 | 59 | def _notimplemented(self, *args, **kwds) -> NoReturn: 60 | """Method shouldn't be called for a quantum random number generator.""" 61 | raise NotImplementedError("quantum source does not have state") 62 | 63 | getstate = setstate = _notimplemented 64 | -------------------------------------------------------------------------------- /src/qrandom/__init__.py: -------------------------------------------------------------------------------- 1 | """ANU Quantum Random Numbers. 2 | 3 | Implements a quantum random number generator as a subclass of random.Random 4 | as described on https://docs.python.org/3/library/random.html. The numbers 5 | come from the ANU Quantum Random Number Generator at The Australian National 6 | University (https://quantumnumbers.anu.edu.au/). 7 | 8 | You can use this module just like the standard random module. The module 9 | replaces the default Mersenne Twister generator. Seeding is ignored 10 | and getstate() and setstate() are not implemented because there is no state. 11 | Also, getrandbits() is not available so randrange() can't cover arbitrarily 12 | large ranges. There is no randbytes() because getrandbits() is not available. 13 | 14 | """ 15 | 16 | import sys 17 | 18 | from ._generator import QuantumRandom 19 | 20 | __all__ = [ 21 | "QuantumRandom", 22 | "betavariate", 23 | "choice", 24 | "choices", 25 | "expovariate", 26 | "gammavariate", 27 | "gauss", 28 | "getstate", 29 | "lognormvariate", 30 | "normalvariate", 31 | "paretovariate", 32 | "randint", 33 | "random", 34 | "randrange", 35 | "sample", 36 | "seed", 37 | "setstate", 38 | "shuffle", 39 | "triangular", 40 | "uniform", 41 | "vonmisesvariate", 42 | "weibullvariate", 43 | "fill", 44 | ] 45 | 46 | 47 | _inst = QuantumRandom() 48 | betavariate = _inst.betavariate 49 | 50 | if (sys.version_info.major, sys.version_info.minor) >= (3, 12): 51 | binomialvariate = _inst.binomialvariate # type: ignore[attr-defined] 52 | __all__.append("binomialvariate") 53 | 54 | choice = _inst.choice 55 | choices = _inst.choices 56 | expovariate = _inst.expovariate 57 | gammavariate = _inst.gammavariate 58 | gauss = _inst.gauss 59 | getstate = _inst.getstate 60 | lognormvariate = _inst.lognormvariate 61 | normalvariate = _inst.normalvariate 62 | paretovariate = _inst.paretovariate 63 | randint = _inst.randint 64 | random = _inst.random 65 | randrange = _inst.randrange 66 | sample = _inst.sample 67 | seed = _inst.seed 68 | setstate = _inst.setstate 69 | shuffle = _inst.shuffle 70 | triangular = _inst.triangular 71 | uniform = _inst.uniform 72 | vonmisesvariate = _inst.vonmisesvariate 73 | weibullvariate = _inst.weibullvariate 74 | fill = _inst.fill 75 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import pytest 4 | import responses 5 | 6 | from qrandom import _api, _generator 7 | 8 | 9 | @pytest.fixture 10 | def mocked_responses(): 11 | with responses.RequestsMock() as rsps: 12 | yield rsps 13 | 14 | 15 | @pytest.fixture 16 | def test_responses(): 17 | with open("tests/data/responses.json") as f: 18 | return json.load(f) 19 | 20 | 21 | @pytest.fixture 22 | def anu_url(): 23 | return "https://api.quantumnumbers.anu.edu.au" 24 | 25 | 26 | @pytest.fixture 27 | def api_client_with_successful_api_call( 28 | mocked_responses, anu_url, test_responses 29 | ): 30 | mocked_responses.get( 31 | anu_url, 32 | json={"data": test_responses[0]["data"], "success": True}, 33 | status=200, 34 | ) 35 | return _api.Client("key") 36 | 37 | 38 | @pytest.fixture 39 | def api_client_with_failed_api_call(mocked_responses, anu_url): 40 | mocked_responses.get( 41 | anu_url, 42 | json={"success": False}, 43 | status=400, 44 | ) 45 | return _api.Client("key") 46 | 47 | 48 | @pytest.fixture 49 | def api_client_with_failed_api_call_and_no_json_response( 50 | mocked_responses, anu_url 51 | ): 52 | mocked_responses.get( 53 | anu_url, 54 | status=400, 55 | ) 56 | return _api.Client("key") 57 | 58 | 59 | @pytest.fixture 60 | def api_client_with_failed_api_call_with_200_status(mocked_responses, anu_url): 61 | mocked_responses.get( 62 | anu_url, 63 | json={"success": False}, 64 | status=200, 65 | ) 66 | return _api.Client("key") 67 | 68 | 69 | @pytest.fixture 70 | def api_client_with_mocked_fetch_hex_raw(mocker, test_responses): 71 | mocker.patch( 72 | "qrandom._api.Client.fetch_hex_raw", 73 | return_value=test_responses[0], 74 | ) 75 | return _api.Client("key") 76 | 77 | 78 | @pytest.fixture 79 | def quantum_random_with_no_api_calls(): 80 | return _generator.QuantumRandom() 81 | 82 | 83 | @pytest.fixture 84 | def quantum_random_with_mocked_fetch_hex_raw(mocker, test_responses): 85 | mocker.patch( 86 | "qrandom._api.Client.fetch_hex_raw", 87 | return_value=test_responses[0], 88 | ) 89 | return _generator.QuantumRandom() 90 | 91 | 92 | @pytest.fixture 93 | def quantum_random_with_mocked_fetch_hex_raw_twice(mocker, test_responses): 94 | mocker.patch( 95 | "qrandom._api.Client.fetch_hex_raw", 96 | side_effect=[test_responses[0], test_responses[1]], 97 | ) 98 | return _generator.QuantumRandom() 99 | 100 | 101 | @pytest.fixture 102 | def quantum_random_with_mocked_fetch_hex_raw_five_times( 103 | mocker, test_responses 104 | ): 105 | mocker.patch( 106 | "qrandom._api.Client.fetch_hex_raw", 107 | side_effect=[test_responses[i] for i in range(5)], 108 | ) 109 | return _generator.QuantumRandom() 110 | 111 | 112 | @pytest.fixture 113 | def quantum_random_with_mocked_fetch_hex_raw_for_all_data( 114 | mocker, test_responses 115 | ): 116 | mocker.patch( 117 | "qrandom._api.Client.fetch_hex_raw", 118 | side_effect=test_responses, 119 | ) 120 | return _generator.QuantumRandom() 121 | -------------------------------------------------------------------------------- /tests/test_generator.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from qrandom import _generator 4 | 5 | 6 | def test_notimplemented_raises_on_call(quantum_random_with_no_api_calls): 7 | with pytest.raises(NotImplementedError) as exc_info: 8 | quantum_random_with_no_api_calls._notimplemented() 9 | assert exc_info.value.args[0] == "quantum source does not have state" 10 | 11 | 12 | def test_get_state_raises_on_call(quantum_random_with_no_api_calls): 13 | with pytest.raises(NotImplementedError) as exc_info: 14 | quantum_random_with_no_api_calls.getstate() 15 | assert exc_info.value.args[0] == "quantum source does not have state" 16 | 17 | 18 | def test_set_state_raises_on_call(quantum_random_with_no_api_calls): 19 | with pytest.raises(NotImplementedError) as exc_info: 20 | quantum_random_with_no_api_calls.setstate() 21 | assert exc_info.value.args[0] == "quantum source does not have state" 22 | 23 | 24 | def test_seed_warns_on_call(quantum_random_with_no_api_calls): 25 | with pytest.warns( 26 | UserWarning, match=quantum_random_with_no_api_calls.seed.__doc__ 27 | ): 28 | quantum_random_with_no_api_calls.seed() 29 | 30 | 31 | def test_fill_gets_1024_nums(quantum_random_with_mocked_fetch_hex_raw): 32 | quantum_random_with_mocked_fetch_hex_raw.fill() 33 | assert len(quantum_random_with_mocked_fetch_hex_raw._rand_int64) == 1024 34 | 35 | 36 | def test_fill_gets_2048_nums_after_two_calls( 37 | quantum_random_with_mocked_fetch_hex_raw_twice, 38 | ): 39 | quantum_random_with_mocked_fetch_hex_raw_twice.fill(2) 40 | assert ( 41 | len(quantum_random_with_mocked_fetch_hex_raw_twice._rand_int64) == 2048 42 | ) 43 | 44 | 45 | def test_get_rand_int64(quantum_random_with_mocked_fetch_hex_raw_five_times): 46 | for call in range(1024 * 5): 47 | quantum_random_with_mocked_fetch_hex_raw_five_times._get_rand_int64() 48 | assert ( 49 | len( 50 | quantum_random_with_mocked_fetch_hex_raw_five_times._rand_int64 51 | ) 52 | == (1024 - call - 1) % 1024 53 | ) 54 | 55 | 56 | def test_rand_int64_has_1023_nums_after_call_to_random( 57 | quantum_random_with_mocked_fetch_hex_raw, 58 | ): 59 | quantum_random_with_mocked_fetch_hex_raw.random() 60 | assert len(quantum_random_with_mocked_fetch_hex_raw._rand_int64) == 1023 61 | 62 | 63 | def test_random_returns_in_correct_range( 64 | quantum_random_with_mocked_fetch_hex_raw_for_all_data, 65 | ): 66 | for _ in range(1024 * 10): 67 | number = quantum_random_with_mocked_fetch_hex_raw_for_all_data.random() 68 | assert number >= 0.0 69 | assert number < 1.0 70 | 71 | 72 | def test_quantum_random_constructs_correctly_by_default(): 73 | quantum_random = _generator.QuantumRandom() 74 | assert not quantum_random._rand_int64 75 | assert quantum_random._api_client.key == "key" 76 | assert quantum_random._api_client.params == { 77 | "length": 1024, 78 | "type": "hex16", 79 | "size": 4, 80 | } 81 | 82 | 83 | def test_quantum_random_raises_for_batch_size_out_of_bounds(): 84 | with pytest.raises(ValueError) as exc_info: 85 | _generator.QuantumRandom(batch_size=-1) 86 | assert exc_info.value.args[0] == "batch_size must be > 0 and up to 1024" 87 | with pytest.raises(ValueError) as exc_info: 88 | _generator.QuantumRandom(batch_size=1025) 89 | assert exc_info.value.args[0] == "batch_size must be > 0 and up to 1024" 90 | -------------------------------------------------------------------------------- /src/qrandom/_api.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | import os 3 | import pathlib 4 | from typing import Dict, List, Optional, TypedDict, Union 5 | 6 | import requests 7 | import xdg 8 | 9 | 10 | def find_api_key() -> Union[str, None]: 11 | """Return the ANU API key if found, otherwise, return None. 12 | 13 | 1. Return QRANDOM_API_KEY if defined. 14 | 2. Get the config file as $QRANDOM_CONFIG_DIR/qrandom.ini (defaulting 15 | to the XDG home config directory if QRANDOM_CONFIG_DIR is not defined). 16 | 3. Read the key from the config file if the file exists, otherwise, return 17 | None. 18 | 19 | """ 20 | api_key = os.getenv("QRANDOM_API_KEY") 21 | if api_key is not None: 22 | return api_key 23 | 24 | config_path = ( 25 | pathlib.Path( 26 | os.getenv( 27 | "QRANDOM_CONFIG_DIR", str(xdg.xdg_config_home() / "qrandom") 28 | ) 29 | ) 30 | .expanduser() 31 | .resolve() 32 | ) / "qrandom.ini" 33 | 34 | if config_path.exists(): 35 | config = configparser.ConfigParser() 36 | config.read(config_path) 37 | return config["default"]["key"] 38 | else: 39 | return None 40 | 41 | 42 | class Response(TypedDict): 43 | success: bool 44 | type: str 45 | length: str 46 | data: List[str] 47 | 48 | 49 | class Client: 50 | url = "https://api.quantumnumbers.anu.edu.au" 51 | 52 | def __init__( 53 | self, key: Optional[str] = None, batch_size: int = 1024 54 | ) -> None: 55 | """ANU API client. 56 | 57 | The API key can be obtained from https://quantumnumbers.anu.edu.au/pricing. 58 | batch_size is the number of numbers fetched (1024 by default). 59 | 60 | """ # noqa: E501 61 | self.key = key 62 | self.params: Dict[str, Union[int, str]] = { 63 | "length": batch_size, 64 | "type": "hex16", 65 | "size": 4, 66 | } 67 | return 68 | 69 | def fetch_hex_raw(self) -> Response: 70 | """Gets hexadecimal random numbers from the ANU API. 71 | 72 | The output is the raw JSON from the API. Raises HTTPError if the ANU 73 | API call is not successful. This includes the case of 74 | batch_size > 1024. 75 | 76 | """ 77 | if self.key is None: 78 | raise RuntimeError( 79 | "API key not set (set QRANDOM_API_KEY or run qrandom-init)" 80 | ) 81 | response = requests.get( 82 | self.url, params=self.params, headers={"x-api-key": self.key} 83 | ) 84 | try: 85 | response.raise_for_status() 86 | except requests.HTTPError as e: 87 | try: 88 | # Extend the error message with more info if available as JSON 89 | e.args = ((f"{e.args[0]}\nMore info: {e.response.json()}"),) 90 | raise e 91 | except requests.JSONDecodeError: 92 | raise e 93 | r_json = response.json() 94 | if not r_json["success"]: 95 | # This used to happen with the old API so keeping it here just 96 | # in case 97 | raise requests.HTTPError( 98 | "the 'success' field in the ANU response was False even " 99 | f"though the status code was {response.status_code}" 100 | ) 101 | return r_json 102 | 103 | def fetch_hex(self) -> List[str]: 104 | """Gets hexadecimal random numbers from the ANU API. 105 | 106 | Calls Client.fetch_hex_raw(batch_size) and processes the response. 107 | 108 | """ 109 | return self.fetch_hex_raw()["data"] 110 | 111 | def fetch_int64(self) -> List[int]: 112 | """Gets random int64s from the ANU API. 113 | 114 | Calls Client.fetch_hex(batch_size) and converts the hex numbers to 115 | ints. 116 | 117 | """ 118 | return [int(number, 16) for number in self.fetch_hex()] 119 | -------------------------------------------------------------------------------- /tests/test_cli.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | 3 | import xdg 4 | from click.testing import CliRunner 5 | 6 | from qrandom import _cli 7 | 8 | 9 | def test_default_flow(tmp_path, mocker): 10 | config_dir = tmp_path / ".config" 11 | mocker.patch("xdg.xdg_config_home", return_value=config_dir) 12 | runner = CliRunner() 13 | with runner.isolated_filesystem(temp_dir=tmp_path): 14 | result = runner.invoke(_cli.main, input="\nmy-key") 15 | assert result.exit_code == 0 16 | assert result.output == ( 17 | "Where would you like to store the key? " 18 | f"[{config_dir / 'qrandom'}]: \n" 19 | "Enter your API key: my-key\n" 20 | f"Stored API key in {config_dir / 'qrandom/qrandom.ini'}.\n" 21 | ) 22 | config = configparser.ConfigParser() 23 | config.read(config_dir / "qrandom/qrandom.ini") 24 | assert config["default"]["key"] == "my-key" 25 | 26 | 27 | def test_user_provides_custom_dir(tmp_path): 28 | config_dir = tmp_path / "key-dir" 29 | runner = CliRunner() 30 | with runner.isolated_filesystem(temp_dir=tmp_path): 31 | result = runner.invoke(_cli.main, input=f"{config_dir}\nmy-key") 32 | assert result.exit_code == 0 33 | assert result.output == ( 34 | "Where would you like to store the key? " 35 | f"[{xdg.xdg_config_home() / 'qrandom'}]: {config_dir}\n" 36 | "Enter your API key: my-key\n" 37 | f"Stored API key in {config_dir / 'qrandom.ini'}.\n" 38 | "Since you did not write to the default path, do not forget to " 39 | f"set QRANDOM_CONFIG_DIR to {config_dir}.\n" 40 | ) 41 | config = configparser.ConfigParser() 42 | config.read(config_dir / "qrandom.ini") 43 | assert config["default"]["key"] == "my-key" 44 | 45 | 46 | def test_quits_if_config_is_not_a_directory(tmp_path): 47 | config_path = tmp_path / "key" 48 | with open(config_path, "w") as f: 49 | f.write("xyz") 50 | runner = CliRunner() 51 | with runner.isolated_filesystem(temp_dir=tmp_path): 52 | result = runner.invoke(_cli.main, input=f"{config_path}") 53 | assert result.exit_code == 1 54 | assert result.output == ( 55 | "Where would you like to store the key? " 56 | f"[{xdg.xdg_config_home() / 'qrandom'}]: {config_path}\n" 57 | f"{config_path} is not a directory.\n" 58 | ) 59 | 60 | 61 | def test_confirm_overwrite(tmp_path): 62 | config_dir = tmp_path / "key-dir" 63 | config_dir.mkdir() 64 | config_path = config_dir / "qrandom.ini" 65 | with open(config_path, "w") as f: 66 | f.write("xyz") 67 | runner = CliRunner() 68 | with runner.isolated_filesystem(temp_dir=tmp_path): 69 | result = runner.invoke(_cli.main, input=f"{config_dir}\ny\nmy-key") 70 | assert result.exit_code == 0 71 | assert result.output == ( 72 | "Where would you like to store the key? " 73 | f"[{xdg.xdg_config_home() / 'qrandom'}]: {config_dir}\n" 74 | f"Would you like to overwrite {config_path}? [y/N]: y\n" 75 | "Enter your API key: my-key\n" 76 | f"Stored API key in {config_dir / 'qrandom.ini'}.\n" 77 | "Since you did not write to the default path, do not forget to " 78 | f"set QRANDOM_CONFIG_DIR to {config_dir}.\n" 79 | ) 80 | config = configparser.ConfigParser() 81 | config.read(config_dir / "qrandom.ini") 82 | assert config["default"]["key"] == "my-key" 83 | 84 | 85 | def test_do_not_overwrite(tmp_path): 86 | config_dir = tmp_path / "key-dir" 87 | config_dir.mkdir() 88 | config_path = config_dir / "qrandom.ini" 89 | with open(config_path, "w") as f: 90 | f.write("xyz") 91 | runner = CliRunner() 92 | with runner.isolated_filesystem(temp_dir=tmp_path): 93 | result = runner.invoke(_cli.main, input=f"{config_dir}\nn\nmy-key") 94 | assert result.exit_code == 1 95 | assert result.output == ( 96 | "Where would you like to store the key? " 97 | f"[{xdg.xdg_config_home() / 'qrandom'}]: {config_dir}\n" 98 | f"Would you like to overwrite {config_path}? [y/N]: n\n" 99 | "Aborted!\n" 100 | ) 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quantum random numbers in Python 2 | 3 | [![Tests](https://img.shields.io/github/actions/workflow/status/sbalian/quantum-random/tests.yml?label=tests 4 | )](https://github.com/sbalian/quantum-random/actions/workflows/tests.yml) 5 | [![Version](https://img.shields.io/pypi/v/quantum-random)](https://pypi.org/project/quantum-random/) 6 | ![Python Versions](https://img.shields.io/pypi/pyversions/quantum-random) 7 | [![Download Stats](https://img.shields.io/pypi/dm/quantum-random)](https://pypistats.org/packages/quantum-random) 8 | ![License](https://img.shields.io/github/license/sbalian/quantum-random) 9 | 10 | Use the [Python random module][pyrandom] with real quantum random numbers from 11 | [ANU][anu]. The default pseudo-random generator is replaced by calls to 12 | the ANU API. 13 | 14 | ## Usage 15 | 16 | Import `qrandom` and use it like the standard `random` module. For example: 17 | 18 | ```python 19 | >>> import qrandom 20 | 21 | >>> qrandom.random() 22 | 0.15357449726583722 23 | 24 | >>> qrandom.sample(range(10), 2) 25 | [6, 4] 26 | 27 | >>> qrandom.gauss(0.0, 1.0) 28 | -0.8370871276247828 29 | ``` 30 | 31 | Alternatively, you can use the class `qrandom.QuantumRandom`. It has the same 32 | interface as `random.Random`. 33 | 34 | There is also a [NumPy][numpy] interface, although it is not fully tested: 35 | 36 | ```python 37 | >>> from qrandom.numpy import quantum_rng 38 | 39 | >>> qrng = quantum_rng() 40 | 41 | >>> qrng.random((3, 3)) # use like numpy.random.default_rng() 42 | array([[0.37220278, 0.24337193, 0.67534826], 43 | [0.209068 , 0.25108681, 0.49201691], 44 | [0.35894084, 0.72219929, 0.55388594]]) 45 | ``` 46 | 47 | NumPy is supported using [RandomGen][randomgen]. 48 | 49 | ## Installation 50 | 51 | The minimum supported Python version is 3.9. Install with `pip`: 52 | 53 | ```bash 54 | pip install -U quantum-random 55 | ``` 56 | 57 | If you want NumPy support: 58 | 59 | ```bash 60 | pip install -U 'quantum-random[numpy]' 61 | ``` 62 | 63 | ## First-time setup: setting your API key 64 | 65 | ANU requires you to use an API key. You can get a free trial or pay for a key 66 | [here][anupricing]. 67 | 68 | You can pass your key to `qrandom` in three ways: 69 | 70 | 1. By setting the environment variable `QRANDOM_API_KEY`. 71 | 2. By running the included command line utility `qrandom-init` to save your 72 | key in `qrandom.ini` in a subdirectory of your home config directory 73 | as specified by XDG, e.g., `/home//.config/qrandom/`. 74 | 3. By running `qrandom-init` to save your key in `qrandom.ini` in a directory 75 | of your choice, and then specifying this directory by setting 76 | `QRANDOM_CONFIG_DIR`. 77 | 78 | If `QRANDOM_API_KEY` is set, its value is used as the API key and the 79 | config file is not read. Otherwise, `qrandom` will look for the key 80 | in the config directory. The config directory defaults to the XDG home config 81 | and can be changed by setting `QRANDOM_CONFIG_DIR`. 82 | 83 | ## Pre-fetching batches 84 | 85 | Batches of quantum numbers are fetched from the API as needed. 86 | Each batch contains 1024 numbers. Use `qrandom.fill(n)` to fetch `n` batches 87 | if you need to pre-fetch at the start of your computation. 88 | 89 | ## Tests 90 | 91 | The tests run for Python 3.9 - 3.12 on the latest Windows, 92 | macOS and Ubuntu runner images. 93 | 94 | See [here](./analysis/uniform.md) for a visualisation and a Kolmogorov–Smirnov 95 | test. 96 | 97 | ## Notes on implementation 98 | 99 | The `qrandom` module exposes a class derived from `random.Random` with a 100 | `random()` method that outputs quantum floats in the range [0, 1) 101 | (converted from 64-bit integers). Overriding `random.Random.random` 102 | is sufficient to make the `qrandom` module behave mostly like the 103 | `random` module as described in the [Python docs][pyrandom]. The exceptions 104 | are `getrandbits()` and `randbytes()`: these are not available in 105 | `qrandom`. Because `getrandbits()` is not available, `randrange()` cannot 106 | produce arbitrarily long sequences. Finally, the user is warned when `seed()` 107 | is called because the quantum generator has no state. For the same reason, 108 | `getstate()` and `setstate()` are not implemented. 109 | 110 | ## License 111 | 112 | See [LICENCE](./LICENSE). 113 | 114 | [anu]: https://quantumnumbers.anu.edu.au 115 | [anupricing]: https://quantumnumbers.anu.edu.au/pricing 116 | [pyrandom]: https://docs.python.org/3/library/random.html 117 | [numpy]: https://numpy.org 118 | [randomgen]: https://github.com/bashtage/randomgen 119 | -------------------------------------------------------------------------------- /tests/test_api.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | import requests 5 | 6 | from qrandom import _api 7 | 8 | 9 | def test_client_url(anu_url): 10 | client = _api.Client() 11 | assert client.url == anu_url 12 | 13 | 14 | def test_client_constructs_correctly_by_default(): 15 | client = _api.Client() 16 | assert client.key is None 17 | assert client.params == { 18 | "length": 1024, 19 | "type": "hex16", 20 | "size": 4, 21 | } 22 | 23 | 24 | def test_client_constructs_correctly_passing_batch_size(): 25 | client = _api.Client(batch_size=10) 26 | assert client.key is None 27 | assert client.params == { 28 | "length": 10, 29 | "type": "hex16", 30 | "size": 4, 31 | } 32 | 33 | 34 | def test_client_constructs_correctly_passing_key(): 35 | client = _api.Client(key="key") 36 | assert client.key == "key" 37 | assert client.params == { 38 | "length": 1024, 39 | "type": "hex16", 40 | "size": 4, 41 | } 42 | 43 | 44 | def test_fetch_hex_raw_returns_correctly( 45 | api_client_with_successful_api_call, test_responses 46 | ): 47 | r_json = api_client_with_successful_api_call.fetch_hex_raw() 48 | assert r_json == {"data": test_responses[0]["data"], "success": True} 49 | assert len(r_json["data"]) == 1024 50 | 51 | 52 | def test_fetch_hex_raw_returns_correctly_with_set_batch_size( 53 | mocked_responses, test_responses, anu_url 54 | ): 55 | response = test_responses[0] 56 | response["length"] = 1023 57 | response["data"].pop() 58 | mocked_responses.get( 59 | anu_url, 60 | json={"data": response["data"], "success": True}, 61 | status=200, 62 | ) 63 | client = _api.Client("key", batch_size=1023) 64 | r_json = client.fetch_hex_raw() 65 | assert r_json == {"data": response["data"], "success": True} 66 | assert len(r_json["data"]) == 1023 67 | 68 | 69 | def test_fetch_hex_raw_raises_when_api_key_not_found(): 70 | client = _api.Client() 71 | with pytest.raises(RuntimeError) as exc_info: 72 | client.fetch_hex_raw() 73 | assert ( 74 | exc_info.value.args[0] 75 | == "API key not set (set QRANDOM_API_KEY or run qrandom-init)" 76 | ) 77 | 78 | 79 | def test_fetch_hex_raw_raises_on_failed_api_call( 80 | api_client_with_failed_api_call, 81 | ): 82 | with pytest.raises(requests.HTTPError) as exc_info: 83 | api_client_with_failed_api_call.fetch_hex_raw() 84 | assert ( 85 | exc_info.value.args[0] 86 | == "400 Client Error: Bad Request for url: https://api.quantumnumbers.anu.edu.au/?length=1024&type=hex16&size=4\nMore info: {'success': False}" # noqa: E501 87 | ) 88 | 89 | 90 | def test_fetch_hex_raw_raises_on_failed_api_call_with_no_extra_json( 91 | api_client_with_failed_api_call_and_no_json_response, 92 | ): 93 | with pytest.raises(requests.HTTPError) as exc_info: 94 | api_client_with_failed_api_call_and_no_json_response.fetch_hex_raw() 95 | assert ( 96 | exc_info.value.args[0] 97 | == "400 Client Error: Bad Request for url: https://api.quantumnumbers.anu.edu.au/?length=1024&type=hex16&size=4" # noqa: E501 98 | ) 99 | 100 | 101 | def test_fetch_hex_raw_raises_on_failed_api_call_with_200_status( 102 | api_client_with_failed_api_call_with_200_status, 103 | ): 104 | with pytest.raises(requests.HTTPError) as exc_info: 105 | api_client_with_failed_api_call_with_200_status.fetch_hex_raw() 106 | assert ( 107 | exc_info.value.args[0] 108 | == "the 'success' field in the ANU response was False even though the status code was 200" # noqa: E501 109 | ) 110 | 111 | 112 | def test_fetch_hex_returns_hex_numbers_and_with_correct_length( 113 | api_client_with_mocked_fetch_hex_raw, 114 | ): 115 | numbers = api_client_with_mocked_fetch_hex_raw.fetch_hex() 116 | for number in numbers: 117 | int(number, 16) 118 | assert len(numbers) == 1024 119 | 120 | 121 | def test_fetch_int64_returns_ints_and_with_correct_length( 122 | api_client_with_mocked_fetch_hex_raw, 123 | ): 124 | numbers = api_client_with_mocked_fetch_hex_raw.fetch_int64() 125 | for number in numbers: 126 | assert isinstance(number, int) 127 | assert len(numbers) == 1024 128 | 129 | 130 | def test_fetch_int64_returns_in_correct_range( 131 | api_client_with_mocked_fetch_hex_raw, 132 | ): 133 | numbers = api_client_with_mocked_fetch_hex_raw.fetch_int64() 134 | for number in numbers: 135 | assert 0 <= number < 2**64 136 | 137 | 138 | def test_find_api_key_directly_from_env(): 139 | assert _api.find_api_key() == "key" 140 | 141 | 142 | def test_find_api_key_from_default_config_dir(mocker, tmp_path): 143 | config_dir = tmp_path / "qrandom" 144 | config_dir.mkdir() 145 | environ = { 146 | name: value 147 | for name, value in os.environ.items() 148 | if name != "QRANDOM_API_KEY" 149 | } 150 | mocker.patch.dict(os.environ, environ, clear=True) 151 | with open(config_dir / "qrandom.ini", "w") as f: 152 | f.write("[default]\nkey = key-from-file\n") 153 | mocker.patch("xdg.xdg_config_home", return_value=tmp_path) 154 | assert _api.find_api_key() == "key-from-file" 155 | 156 | 157 | def test_find_api_key_from_set_config_dir(mocker, tmp_path): 158 | config_dir = tmp_path / "qrandom" 159 | config_dir.mkdir() 160 | environ = { 161 | name: value 162 | for name, value in os.environ.items() 163 | if name != "QRANDOM_API_KEY" 164 | } 165 | environ["QRANDOM_CONFIG_DIR"] = str(config_dir) 166 | mocker.patch.dict(os.environ, environ, clear=True) 167 | with open(config_dir / "qrandom.ini", "w") as f: 168 | f.write("[default]\nkey = key-from-file\n") 169 | assert _api.find_api_key() == "key-from-file" 170 | 171 | 172 | def test_find_api_key_returns_none_if_config_doesnt_exist_and_env_var_not_set( 173 | mocker, tmp_path 174 | ): 175 | config_dir = tmp_path / "qrandom" 176 | config_dir.mkdir() 177 | environ = { 178 | name: value 179 | for name, value in os.environ.items() 180 | if name != "QRANDOM_API_KEY" 181 | } 182 | environ["QRANDOM_CONFIG_DIR"] = str(config_dir) 183 | mocker.patch.dict(os.environ, environ, clear=True) 184 | assert _api.find_api_key() is None 185 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | requires-python = ">=3.9" 3 | 4 | [[package]] 5 | name = "black" 6 | version = "24.10.0" 7 | source = { registry = "https://pypi.org/simple" } 8 | dependencies = [ 9 | { name = "click" }, 10 | { name = "mypy-extensions" }, 11 | { name = "packaging" }, 12 | { name = "pathspec" }, 13 | { name = "platformdirs" }, 14 | { name = "tomli", marker = "python_full_version < '3.11'" }, 15 | { name = "typing-extensions", marker = "python_full_version < '3.11'" }, 16 | ] 17 | sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } 18 | wheels = [ 19 | { url = "https://files.pythonhosted.org/packages/a3/f3/465c0eb5cddf7dbbfe1fecd9b875d1dcf51b88923cd2c1d7e9ab95c6336b/black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", size = 1623211 }, 20 | { url = "https://files.pythonhosted.org/packages/df/57/b6d2da7d200773fdfcc224ffb87052cf283cec4d7102fab450b4a05996d8/black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", size = 1457139 }, 21 | { url = "https://files.pythonhosted.org/packages/6e/c5/9023b7673904a5188f9be81f5e129fff69f51f5515655fbd1d5a4e80a47b/black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", size = 1753774 }, 22 | { url = "https://files.pythonhosted.org/packages/e1/32/df7f18bd0e724e0d9748829765455d6643ec847b3f87e77456fc99d0edab/black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e", size = 1414209 }, 23 | { url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 }, 24 | { url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 }, 25 | { url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 }, 26 | { url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 }, 27 | { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, 28 | { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, 29 | { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, 30 | { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, 31 | { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, 32 | { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, 33 | { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, 34 | { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, 35 | { url = "https://files.pythonhosted.org/packages/fe/02/f408c804e0ee78c367dcea0a01aedde4f1712af93b8b6e60df981e0228c7/black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd", size = 1622516 }, 36 | { url = "https://files.pythonhosted.org/packages/f8/b9/9b706ed2f55bfb28b436225a9c57da35990c9005b90b8c91f03924454ad7/black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f", size = 1456181 }, 37 | { url = "https://files.pythonhosted.org/packages/0a/1c/314d7f17434a5375682ad097f6f4cc0e3f414f3c95a9b1bb4df14a0f11f9/black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800", size = 1752801 }, 38 | { url = "https://files.pythonhosted.org/packages/39/a7/20e5cd9237d28ad0b31438de5d9f01c8b99814576f4c0cda1edd62caf4b0/black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7", size = 1413626 }, 39 | { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, 40 | ] 41 | 42 | [[package]] 43 | name = "certifi" 44 | version = "2024.8.30" 45 | source = { registry = "https://pypi.org/simple" } 46 | sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } 47 | wheels = [ 48 | { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, 49 | ] 50 | 51 | [[package]] 52 | name = "charset-normalizer" 53 | version = "3.4.0" 54 | source = { registry = "https://pypi.org/simple" } 55 | sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } 56 | wheels = [ 57 | { url = "https://files.pythonhosted.org/packages/69/8b/825cc84cf13a28bfbcba7c416ec22bf85a9584971be15b21dd8300c65b7f/charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", size = 196363 }, 58 | { url = "https://files.pythonhosted.org/packages/23/81/d7eef6a99e42c77f444fdd7bc894b0ceca6c3a95c51239e74a722039521c/charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", size = 125639 }, 59 | { url = "https://files.pythonhosted.org/packages/21/67/b4564d81f48042f520c948abac7079356e94b30cb8ffb22e747532cf469d/charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", size = 120451 }, 60 | { url = "https://files.pythonhosted.org/packages/c2/72/12a7f0943dd71fb5b4e7b55c41327ac0a1663046a868ee4d0d8e9c369b85/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", size = 140041 }, 61 | { url = "https://files.pythonhosted.org/packages/67/56/fa28c2c3e31217c4c52158537a2cf5d98a6c1e89d31faf476c89391cd16b/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", size = 150333 }, 62 | { url = "https://files.pythonhosted.org/packages/f9/d2/466a9be1f32d89eb1554cf84073a5ed9262047acee1ab39cbaefc19635d2/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", size = 142921 }, 63 | { url = "https://files.pythonhosted.org/packages/f8/01/344ec40cf5d85c1da3c1f57566c59e0c9b56bcc5566c08804a95a6cc8257/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", size = 144785 }, 64 | { url = "https://files.pythonhosted.org/packages/73/8b/2102692cb6d7e9f03b9a33a710e0164cadfce312872e3efc7cfe22ed26b4/charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", size = 146631 }, 65 | { url = "https://files.pythonhosted.org/packages/d8/96/cc2c1b5d994119ce9f088a9a0c3ebd489d360a2eb058e2c8049f27092847/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", size = 140867 }, 66 | { url = "https://files.pythonhosted.org/packages/c9/27/cde291783715b8ec30a61c810d0120411844bc4c23b50189b81188b273db/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", size = 149273 }, 67 | { url = "https://files.pythonhosted.org/packages/3a/a4/8633b0fc1a2d1834d5393dafecce4a1cc56727bfd82b4dc18fc92f0d3cc3/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", size = 152437 }, 68 | { url = "https://files.pythonhosted.org/packages/64/ea/69af161062166b5975ccbb0961fd2384853190c70786f288684490913bf5/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", size = 150087 }, 69 | { url = "https://files.pythonhosted.org/packages/3b/fd/e60a9d9fd967f4ad5a92810138192f825d77b4fa2a557990fd575a47695b/charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", size = 145142 }, 70 | { url = "https://files.pythonhosted.org/packages/6d/02/8cb0988a1e49ac9ce2eed1e07b77ff118f2923e9ebd0ede41ba85f2dcb04/charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", size = 94701 }, 71 | { url = "https://files.pythonhosted.org/packages/d6/20/f1d4670a8a723c46be695dff449d86d6092916f9e99c53051954ee33a1bc/charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", size = 102191 }, 72 | { url = "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", size = 193339 }, 73 | { url = "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", size = 124366 }, 74 | { url = "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", size = 118874 }, 75 | { url = "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", size = 138243 }, 76 | { url = "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", size = 148676 }, 77 | { url = "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", size = 141289 }, 78 | { url = "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", size = 142585 }, 79 | { url = "https://files.pythonhosted.org/packages/3b/a0/a68980ab8a1f45a36d9745d35049c1af57d27255eff8c907e3add84cf68f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", size = 144408 }, 80 | { url = "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", size = 139076 }, 81 | { url = "https://files.pythonhosted.org/packages/fb/9d/9c13753a5a6e0db4a0a6edb1cef7aee39859177b64e1a1e748a6e3ba62c2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", size = 146874 }, 82 | { url = "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", size = 150871 }, 83 | { url = "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", size = 148546 }, 84 | { url = "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", size = 143048 }, 85 | { url = "https://files.pythonhosted.org/packages/01/f8/38842422988b795220eb8038745d27a675ce066e2ada79516c118f291f07/charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", size = 94389 }, 86 | { url = "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", size = 101752 }, 87 | { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, 88 | { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, 89 | { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, 90 | { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, 91 | { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, 92 | { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, 93 | { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, 94 | { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, 95 | { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, 96 | { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, 97 | { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, 98 | { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, 99 | { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, 100 | { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, 101 | { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, 102 | { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, 103 | { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, 104 | { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, 105 | { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, 106 | { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, 107 | { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, 108 | { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, 109 | { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, 110 | { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, 111 | { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, 112 | { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, 113 | { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, 114 | { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, 115 | { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, 116 | { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, 117 | { url = "https://files.pythonhosted.org/packages/54/2f/28659eee7f5d003e0f5a3b572765bf76d6e0fe6601ab1f1b1dd4cba7e4f1/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", size = 196326 }, 118 | { url = "https://files.pythonhosted.org/packages/d1/18/92869d5c0057baa973a3ee2af71573be7b084b3c3d428fe6463ce71167f8/charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", size = 125614 }, 119 | { url = "https://files.pythonhosted.org/packages/d6/27/327904c5a54a7796bb9f36810ec4173d2df5d88b401d2b95ef53111d214e/charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", size = 120450 }, 120 | { url = "https://files.pythonhosted.org/packages/a4/23/65af317914a0308495133b2d654cf67b11bbd6ca16637c4e8a38f80a5a69/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", size = 140135 }, 121 | { url = "https://files.pythonhosted.org/packages/f2/41/6190102ad521a8aa888519bb014a74251ac4586cde9b38e790901684f9ab/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", size = 150413 }, 122 | { url = "https://files.pythonhosted.org/packages/7b/ab/f47b0159a69eab9bd915591106859f49670c75f9a19082505ff16f50efc0/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", size = 142992 }, 123 | { url = "https://files.pythonhosted.org/packages/28/89/60f51ad71f63aaaa7e51a2a2ad37919985a341a1d267070f212cdf6c2d22/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", size = 144871 }, 124 | { url = "https://files.pythonhosted.org/packages/0c/48/0050550275fea585a6e24460b42465020b53375017d8596c96be57bfabca/charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", size = 146756 }, 125 | { url = "https://files.pythonhosted.org/packages/dc/b5/47f8ee91455946f745e6c9ddbb0f8f50314d2416dd922b213e7d5551ad09/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", size = 141034 }, 126 | { url = "https://files.pythonhosted.org/packages/84/79/5c731059ebab43e80bf61fa51666b9b18167974b82004f18c76378ed31a3/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", size = 149434 }, 127 | { url = "https://files.pythonhosted.org/packages/ca/f3/0719cd09fc4dc42066f239cb3c48ced17fc3316afca3e2a30a4756fe49ab/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", size = 152443 }, 128 | { url = "https://files.pythonhosted.org/packages/f7/0e/c6357297f1157c8e8227ff337e93fd0a90e498e3d6ab96b2782204ecae48/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", size = 150294 }, 129 | { url = "https://files.pythonhosted.org/packages/54/9a/acfa96dc4ea8c928040b15822b59d0863d6e1757fba8bd7de3dc4f761c13/charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", size = 145314 }, 130 | { url = "https://files.pythonhosted.org/packages/73/1c/b10a63032eaebb8d7bcb8544f12f063f41f5f463778ac61da15d9985e8b6/charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", size = 94724 }, 131 | { url = "https://files.pythonhosted.org/packages/c5/77/3a78bf28bfaa0863f9cfef278dbeadf55efe064eafff8c7c424ae3c4c1bf/charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", size = 102159 }, 132 | { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, 133 | ] 134 | 135 | [[package]] 136 | name = "click" 137 | version = "8.1.7" 138 | source = { registry = "https://pypi.org/simple" } 139 | dependencies = [ 140 | { name = "colorama", marker = "platform_system == 'Windows'" }, 141 | ] 142 | sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } 143 | wheels = [ 144 | { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, 145 | ] 146 | 147 | [[package]] 148 | name = "colorama" 149 | version = "0.4.6" 150 | source = { registry = "https://pypi.org/simple" } 151 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } 152 | wheels = [ 153 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, 154 | ] 155 | 156 | [[package]] 157 | name = "exceptiongroup" 158 | version = "1.2.2" 159 | source = { registry = "https://pypi.org/simple" } 160 | sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } 161 | wheels = [ 162 | { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, 163 | ] 164 | 165 | [[package]] 166 | name = "flake8" 167 | version = "7.1.1" 168 | source = { registry = "https://pypi.org/simple" } 169 | dependencies = [ 170 | { name = "mccabe" }, 171 | { name = "pycodestyle" }, 172 | { name = "pyflakes" }, 173 | ] 174 | sdist = { url = "https://files.pythonhosted.org/packages/37/72/e8d66150c4fcace3c0a450466aa3480506ba2cae7b61e100a2613afc3907/flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38", size = 48054 } 175 | wheels = [ 176 | { url = "https://files.pythonhosted.org/packages/d9/42/65004373ac4617464f35ed15931b30d764f53cdd30cc78d5aea349c8c050/flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213", size = 57731 }, 177 | ] 178 | 179 | [[package]] 180 | name = "idna" 181 | version = "3.10" 182 | source = { registry = "https://pypi.org/simple" } 183 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } 184 | wheels = [ 185 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, 186 | ] 187 | 188 | [[package]] 189 | name = "iniconfig" 190 | version = "2.0.0" 191 | source = { registry = "https://pypi.org/simple" } 192 | sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } 193 | wheels = [ 194 | { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, 195 | ] 196 | 197 | [[package]] 198 | name = "isort" 199 | version = "5.13.2" 200 | source = { registry = "https://pypi.org/simple" } 201 | sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303 } 202 | wheels = [ 203 | { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310 }, 204 | ] 205 | 206 | [[package]] 207 | name = "mccabe" 208 | version = "0.7.0" 209 | source = { registry = "https://pypi.org/simple" } 210 | sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658 } 211 | wheels = [ 212 | { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350 }, 213 | ] 214 | 215 | [[package]] 216 | name = "mypy" 217 | version = "1.13.0" 218 | source = { registry = "https://pypi.org/simple" } 219 | dependencies = [ 220 | { name = "mypy-extensions" }, 221 | { name = "tomli", marker = "python_full_version < '3.11'" }, 222 | { name = "typing-extensions" }, 223 | ] 224 | sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 } 225 | wheels = [ 226 | { url = "https://files.pythonhosted.org/packages/5e/8c/206de95a27722b5b5a8c85ba3100467bd86299d92a4f71c6b9aa448bfa2f/mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a", size = 11020731 }, 227 | { url = "https://files.pythonhosted.org/packages/ab/bb/b31695a29eea76b1569fd28b4ab141a1adc9842edde080d1e8e1776862c7/mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80", size = 10184276 }, 228 | { url = "https://files.pythonhosted.org/packages/a5/2d/4a23849729bb27934a0e079c9c1aad912167d875c7b070382a408d459651/mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7", size = 12587706 }, 229 | { url = "https://files.pythonhosted.org/packages/5c/c3/d318e38ada50255e22e23353a469c791379825240e71b0ad03e76ca07ae6/mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f", size = 13105586 }, 230 | { url = "https://files.pythonhosted.org/packages/4a/25/3918bc64952370c3dbdbd8c82c363804678127815febd2925b7273d9482c/mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372", size = 9632318 }, 231 | { url = "https://files.pythonhosted.org/packages/d0/19/de0822609e5b93d02579075248c7aa6ceaddcea92f00bf4ea8e4c22e3598/mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d", size = 10939027 }, 232 | { url = "https://files.pythonhosted.org/packages/c8/71/6950fcc6ca84179137e4cbf7cf41e6b68b4a339a1f5d3e954f8c34e02d66/mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d", size = 10108699 }, 233 | { url = "https://files.pythonhosted.org/packages/26/50/29d3e7dd166e74dc13d46050b23f7d6d7533acf48f5217663a3719db024e/mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b", size = 12506263 }, 234 | { url = "https://files.pythonhosted.org/packages/3f/1d/676e76f07f7d5ddcd4227af3938a9c9640f293b7d8a44dd4ff41d4db25c1/mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73", size = 12984688 }, 235 | { url = "https://files.pythonhosted.org/packages/9c/03/5a85a30ae5407b1d28fab51bd3e2103e52ad0918d1e68f02a7778669a307/mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca", size = 9626811 }, 236 | { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 }, 237 | { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 }, 238 | { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 }, 239 | { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 }, 240 | { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 }, 241 | { url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721 }, 242 | { url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996 }, 243 | { url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043 }, 244 | { url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996 }, 245 | { url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709 }, 246 | { url = "https://files.pythonhosted.org/packages/5f/d4/b33ddd40dad230efb317898a2d1c267c04edba73bc5086bf77edeb410fb2/mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc", size = 11013906 }, 247 | { url = "https://files.pythonhosted.org/packages/f4/e6/f414bca465b44d01cd5f4a82761e15044bedd1bf8025c5af3cc64518fac5/mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732", size = 10180657 }, 248 | { url = "https://files.pythonhosted.org/packages/38/e9/fc3865e417722f98d58409770be01afb961e2c1f99930659ff4ae7ca8b7e/mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc", size = 12586394 }, 249 | { url = "https://files.pythonhosted.org/packages/2e/35/f4d8b6d2cb0b3dad63e96caf159419dda023f45a358c6c9ac582ccaee354/mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d", size = 13103591 }, 250 | { url = "https://files.pythonhosted.org/packages/22/1d/80594aef135f921dd52e142fa0acd19df197690bd0cde42cea7b88cf5aa2/mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24", size = 9634690 }, 251 | { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 }, 252 | ] 253 | 254 | [[package]] 255 | name = "mypy-extensions" 256 | version = "1.0.0" 257 | source = { registry = "https://pypi.org/simple" } 258 | sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } 259 | wheels = [ 260 | { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, 261 | ] 262 | 263 | [[package]] 264 | name = "numpy" 265 | version = "2.0.2" 266 | source = { registry = "https://pypi.org/simple" } 267 | sdist = { url = "https://files.pythonhosted.org/packages/a9/75/10dd1f8116a8b796cb2c737b674e02d02e80454bda953fa7e65d8c12b016/numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78", size = 18902015 } 268 | wheels = [ 269 | { url = "https://files.pythonhosted.org/packages/21/91/3495b3237510f79f5d81f2508f9f13fea78ebfdf07538fc7444badda173d/numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece", size = 21165245 }, 270 | { url = "https://files.pythonhosted.org/packages/05/33/26178c7d437a87082d11019292dce6d3fe6f0e9026b7b2309cbf3e489b1d/numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04", size = 13738540 }, 271 | { url = "https://files.pythonhosted.org/packages/ec/31/cc46e13bf07644efc7a4bf68df2df5fb2a1a88d0cd0da9ddc84dc0033e51/numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66", size = 5300623 }, 272 | { url = "https://files.pythonhosted.org/packages/6e/16/7bfcebf27bb4f9d7ec67332ffebee4d1bf085c84246552d52dbb548600e7/numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b", size = 6901774 }, 273 | { url = "https://files.pythonhosted.org/packages/f9/a3/561c531c0e8bf082c5bef509d00d56f82e0ea7e1e3e3a7fc8fa78742a6e5/numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd", size = 13907081 }, 274 | { url = "https://files.pythonhosted.org/packages/fa/66/f7177ab331876200ac7563a580140643d1179c8b4b6a6b0fc9838de2a9b8/numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318", size = 19523451 }, 275 | { url = "https://files.pythonhosted.org/packages/25/7f/0b209498009ad6453e4efc2c65bcdf0ae08a182b2b7877d7ab38a92dc542/numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8", size = 19927572 }, 276 | { url = "https://files.pythonhosted.org/packages/3e/df/2619393b1e1b565cd2d4c4403bdd979621e2c4dea1f8532754b2598ed63b/numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326", size = 14400722 }, 277 | { url = "https://files.pythonhosted.org/packages/22/ad/77e921b9f256d5da36424ffb711ae79ca3f451ff8489eeca544d0701d74a/numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97", size = 6472170 }, 278 | { url = "https://files.pythonhosted.org/packages/10/05/3442317535028bc29cf0c0dd4c191a4481e8376e9f0db6bcf29703cadae6/numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131", size = 15905558 }, 279 | { url = "https://files.pythonhosted.org/packages/8b/cf/034500fb83041aa0286e0fb16e7c76e5c8b67c0711bb6e9e9737a717d5fe/numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448", size = 21169137 }, 280 | { url = "https://files.pythonhosted.org/packages/4a/d9/32de45561811a4b87fbdee23b5797394e3d1504b4a7cf40c10199848893e/numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195", size = 13703552 }, 281 | { url = "https://files.pythonhosted.org/packages/c1/ca/2f384720020c7b244d22508cb7ab23d95f179fcfff33c31a6eeba8d6c512/numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57", size = 5298957 }, 282 | { url = "https://files.pythonhosted.org/packages/0e/78/a3e4f9fb6aa4e6fdca0c5428e8ba039408514388cf62d89651aade838269/numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a", size = 6905573 }, 283 | { url = "https://files.pythonhosted.org/packages/a0/72/cfc3a1beb2caf4efc9d0b38a15fe34025230da27e1c08cc2eb9bfb1c7231/numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669", size = 13914330 }, 284 | { url = "https://files.pythonhosted.org/packages/ba/a8/c17acf65a931ce551fee11b72e8de63bf7e8a6f0e21add4c937c83563538/numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951", size = 19534895 }, 285 | { url = "https://files.pythonhosted.org/packages/ba/86/8767f3d54f6ae0165749f84648da9dcc8cd78ab65d415494962c86fac80f/numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9", size = 19937253 }, 286 | { url = "https://files.pythonhosted.org/packages/df/87/f76450e6e1c14e5bb1eae6836478b1028e096fd02e85c1c37674606ab752/numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15", size = 14414074 }, 287 | { url = "https://files.pythonhosted.org/packages/5c/ca/0f0f328e1e59f73754f06e1adfb909de43726d4f24c6a3f8805f34f2b0fa/numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4", size = 6470640 }, 288 | { url = "https://files.pythonhosted.org/packages/eb/57/3a3f14d3a759dcf9bf6e9eda905794726b758819df4663f217d658a58695/numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc", size = 15910230 }, 289 | { url = "https://files.pythonhosted.org/packages/45/40/2e117be60ec50d98fa08c2f8c48e09b3edea93cfcabd5a9ff6925d54b1c2/numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b", size = 20895803 }, 290 | { url = "https://files.pythonhosted.org/packages/46/92/1b8b8dee833f53cef3e0a3f69b2374467789e0bb7399689582314df02651/numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e", size = 13471835 }, 291 | { url = "https://files.pythonhosted.org/packages/7f/19/e2793bde475f1edaea6945be141aef6c8b4c669b90c90a300a8954d08f0a/numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c", size = 5038499 }, 292 | { url = "https://files.pythonhosted.org/packages/e3/ff/ddf6dac2ff0dd50a7327bcdba45cb0264d0e96bb44d33324853f781a8f3c/numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c", size = 6633497 }, 293 | { url = "https://files.pythonhosted.org/packages/72/21/67f36eac8e2d2cd652a2e69595a54128297cdcb1ff3931cfc87838874bd4/numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692", size = 13621158 }, 294 | { url = "https://files.pythonhosted.org/packages/39/68/e9f1126d757653496dbc096cb429014347a36b228f5a991dae2c6b6cfd40/numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a", size = 19236173 }, 295 | { url = "https://files.pythonhosted.org/packages/d1/e9/1f5333281e4ebf483ba1c888b1d61ba7e78d7e910fdd8e6499667041cc35/numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c", size = 19634174 }, 296 | { url = "https://files.pythonhosted.org/packages/71/af/a469674070c8d8408384e3012e064299f7a2de540738a8e414dcfd639996/numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded", size = 14099701 }, 297 | { url = "https://files.pythonhosted.org/packages/d0/3d/08ea9f239d0e0e939b6ca52ad403c84a2bce1bde301a8eb4888c1c1543f1/numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5", size = 6174313 }, 298 | { url = "https://files.pythonhosted.org/packages/b2/b5/4ac39baebf1fdb2e72585c8352c56d063b6126be9fc95bd2bb5ef5770c20/numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a", size = 15606179 }, 299 | { url = "https://files.pythonhosted.org/packages/43/c1/41c8f6df3162b0c6ffd4437d729115704bd43363de0090c7f913cfbc2d89/numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c", size = 21169942 }, 300 | { url = "https://files.pythonhosted.org/packages/39/bc/fd298f308dcd232b56a4031fd6ddf11c43f9917fbc937e53762f7b5a3bb1/numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd", size = 13711512 }, 301 | { url = "https://files.pythonhosted.org/packages/96/ff/06d1aa3eeb1c614eda245c1ba4fb88c483bee6520d361641331872ac4b82/numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b", size = 5306976 }, 302 | { url = "https://files.pythonhosted.org/packages/2d/98/121996dcfb10a6087a05e54453e28e58694a7db62c5a5a29cee14c6e047b/numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729", size = 6906494 }, 303 | { url = "https://files.pythonhosted.org/packages/15/31/9dffc70da6b9bbf7968f6551967fc21156207366272c2a40b4ed6008dc9b/numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1", size = 13912596 }, 304 | { url = "https://files.pythonhosted.org/packages/b9/14/78635daab4b07c0930c919d451b8bf8c164774e6a3413aed04a6d95758ce/numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd", size = 19526099 }, 305 | { url = "https://files.pythonhosted.org/packages/26/4c/0eeca4614003077f68bfe7aac8b7496f04221865b3a5e7cb230c9d055afd/numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d", size = 19932823 }, 306 | { url = "https://files.pythonhosted.org/packages/f1/46/ea25b98b13dccaebddf1a803f8c748680d972e00507cd9bc6dcdb5aa2ac1/numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d", size = 14404424 }, 307 | { url = "https://files.pythonhosted.org/packages/c8/a6/177dd88d95ecf07e722d21008b1b40e681a929eb9e329684d449c36586b2/numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa", size = 6476809 }, 308 | { url = "https://files.pythonhosted.org/packages/ea/2b/7fc9f4e7ae5b507c1a3a21f0f15ed03e794c1242ea8a242ac158beb56034/numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73", size = 15911314 }, 309 | { url = "https://files.pythonhosted.org/packages/8f/3b/df5a870ac6a3be3a86856ce195ef42eec7ae50d2a202be1f5a4b3b340e14/numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8", size = 21025288 }, 310 | { url = "https://files.pythonhosted.org/packages/2c/97/51af92f18d6f6f2d9ad8b482a99fb74e142d71372da5d834b3a2747a446e/numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4", size = 6762793 }, 311 | { url = "https://files.pythonhosted.org/packages/12/46/de1fbd0c1b5ccaa7f9a005b66761533e2f6a3e560096682683a223631fe9/numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c", size = 19334885 }, 312 | { url = "https://files.pythonhosted.org/packages/cc/dc/d330a6faefd92b446ec0f0dfea4c3207bb1fef3c4771d19cf4543efd2c78/numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385", size = 15828784 }, 313 | ] 314 | 315 | [[package]] 316 | name = "packaging" 317 | version = "24.2" 318 | source = { registry = "https://pypi.org/simple" } 319 | sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } 320 | wheels = [ 321 | { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, 322 | ] 323 | 324 | [[package]] 325 | name = "pathspec" 326 | version = "0.12.1" 327 | source = { registry = "https://pypi.org/simple" } 328 | sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } 329 | wheels = [ 330 | { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, 331 | ] 332 | 333 | [[package]] 334 | name = "pip" 335 | version = "24.3.1" 336 | source = { registry = "https://pypi.org/simple" } 337 | sdist = { url = "https://files.pythonhosted.org/packages/f4/b1/b422acd212ad7eedddaf7981eee6e5de085154ff726459cf2da7c5a184c1/pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99", size = 1931073 } 338 | wheels = [ 339 | { url = "https://files.pythonhosted.org/packages/ef/7d/500c9ad20238fcfcb4cb9243eede163594d7020ce87bd9610c9e02771876/pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed", size = 1822182 }, 340 | ] 341 | 342 | [[package]] 343 | name = "platformdirs" 344 | version = "4.3.6" 345 | source = { registry = "https://pypi.org/simple" } 346 | sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } 347 | wheels = [ 348 | { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, 349 | ] 350 | 351 | [[package]] 352 | name = "pluggy" 353 | version = "1.5.0" 354 | source = { registry = "https://pypi.org/simple" } 355 | sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } 356 | wheels = [ 357 | { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, 358 | ] 359 | 360 | [[package]] 361 | name = "pycodestyle" 362 | version = "2.12.1" 363 | source = { registry = "https://pypi.org/simple" } 364 | sdist = { url = "https://files.pythonhosted.org/packages/43/aa/210b2c9aedd8c1cbeea31a50e42050ad56187754b34eb214c46709445801/pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521", size = 39232 } 365 | wheels = [ 366 | { url = "https://files.pythonhosted.org/packages/3a/d8/a211b3f85e99a0daa2ddec96c949cac6824bd305b040571b82a03dd62636/pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", size = 31284 }, 367 | ] 368 | 369 | [[package]] 370 | name = "pyflakes" 371 | version = "3.2.0" 372 | source = { registry = "https://pypi.org/simple" } 373 | sdist = { url = "https://files.pythonhosted.org/packages/57/f9/669d8c9c86613c9d568757c7f5824bd3197d7b1c6c27553bc5618a27cce2/pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", size = 63788 } 374 | wheels = [ 375 | { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725 }, 376 | ] 377 | 378 | [[package]] 379 | name = "pytest" 380 | version = "8.3.3" 381 | source = { registry = "https://pypi.org/simple" } 382 | dependencies = [ 383 | { name = "colorama", marker = "sys_platform == 'win32'" }, 384 | { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, 385 | { name = "iniconfig" }, 386 | { name = "packaging" }, 387 | { name = "pluggy" }, 388 | { name = "tomli", marker = "python_full_version < '3.11'" }, 389 | ] 390 | sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } 391 | wheels = [ 392 | { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, 393 | ] 394 | 395 | [[package]] 396 | name = "pytest-mock" 397 | version = "3.14.0" 398 | source = { registry = "https://pypi.org/simple" } 399 | dependencies = [ 400 | { name = "pytest" }, 401 | ] 402 | sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 } 403 | wheels = [ 404 | { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863 }, 405 | ] 406 | 407 | [[package]] 408 | name = "pyyaml" 409 | version = "6.0.2" 410 | source = { registry = "https://pypi.org/simple" } 411 | sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } 412 | wheels = [ 413 | { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, 414 | { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, 415 | { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, 416 | { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, 417 | { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, 418 | { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, 419 | { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, 420 | { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, 421 | { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, 422 | { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, 423 | { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, 424 | { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, 425 | { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, 426 | { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, 427 | { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, 428 | { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, 429 | { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, 430 | { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, 431 | { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, 432 | { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, 433 | { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, 434 | { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, 435 | { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, 436 | { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, 437 | { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, 438 | { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, 439 | { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, 440 | { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, 441 | { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, 442 | { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, 443 | { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, 444 | { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, 445 | { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, 446 | { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, 447 | { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, 448 | { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, 449 | { url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777 }, 450 | { url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318 }, 451 | { url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891 }, 452 | { url = "https://files.pythonhosted.org/packages/e9/6c/6e1b7f40181bc4805e2e07f4abc10a88ce4648e7e95ff1abe4ae4014a9b2/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", size = 722614 }, 453 | { url = "https://files.pythonhosted.org/packages/3d/32/e7bd8535d22ea2874cef6a81021ba019474ace0d13a4819c2a4bce79bd6a/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", size = 737360 }, 454 | { url = "https://files.pythonhosted.org/packages/d7/12/7322c1e30b9be969670b672573d45479edef72c9a0deac3bb2868f5d7469/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", size = 699006 }, 455 | { url = "https://files.pythonhosted.org/packages/82/72/04fcad41ca56491995076630c3ec1e834be241664c0c09a64c9a2589b507/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", size = 723577 }, 456 | { url = "https://files.pythonhosted.org/packages/ed/5e/46168b1f2757f1fcd442bc3029cd8767d88a98c9c05770d8b420948743bb/PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", size = 144593 }, 457 | { url = "https://files.pythonhosted.org/packages/19/87/5124b1c1f2412bb95c59ec481eaf936cd32f0fe2a7b16b97b81c4c017a6a/PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", size = 162312 }, 458 | ] 459 | 460 | [[package]] 461 | name = "quantum-random" 462 | version = "1.4.2" 463 | source = { editable = "." } 464 | dependencies = [ 465 | { name = "click" }, 466 | { name = "requests" }, 467 | { name = "xdg" }, 468 | ] 469 | 470 | [package.optional-dependencies] 471 | numpy = [ 472 | { name = "numpy" }, 473 | { name = "randomgen" }, 474 | ] 475 | 476 | [package.dev-dependencies] 477 | dev = [ 478 | { name = "black" }, 479 | { name = "flake8" }, 480 | { name = "isort" }, 481 | { name = "mypy" }, 482 | { name = "pip" }, 483 | { name = "pytest" }, 484 | { name = "pytest-mock" }, 485 | { name = "responses" }, 486 | ] 487 | 488 | [package.metadata] 489 | requires-dist = [ 490 | { name = "click", specifier = ">=8.1.7" }, 491 | { name = "numpy", marker = "extra == 'numpy'", specifier = ">=2.0.2" }, 492 | { name = "randomgen", marker = "extra == 'numpy'", specifier = ">=2.1.1" }, 493 | { name = "requests", specifier = ">=2.32.3" }, 494 | { name = "xdg", specifier = ">=6.0.0" }, 495 | ] 496 | 497 | [package.metadata.requires-dev] 498 | dev = [ 499 | { name = "black", specifier = ">=24.10.0" }, 500 | { name = "flake8", specifier = ">=7.1.1" }, 501 | { name = "isort", specifier = ">=5.13.2" }, 502 | { name = "mypy", specifier = ">=1.13.0" }, 503 | { name = "pip", specifier = ">=24.3.1" }, 504 | { name = "pytest", specifier = ">=8.3.3" }, 505 | { name = "pytest-mock", specifier = ">=3.14.0" }, 506 | { name = "responses", specifier = ">=0.25.3" }, 507 | ] 508 | 509 | [[package]] 510 | name = "randomgen" 511 | version = "2.1.1" 512 | source = { registry = "https://pypi.org/simple" } 513 | dependencies = [ 514 | { name = "numpy" }, 515 | ] 516 | sdist = { url = "https://files.pythonhosted.org/packages/cb/65/14c662297f30b78c9a7482d8326fcac54992bcf180a8ffba7500b91d2335/randomgen-2.1.1.tar.gz", hash = "sha256:2f402afff92d2025e0a054bd5aa3069bed476951f18a5476c715cb695f3c418b", size = 1542800 } 517 | wheels = [ 518 | { url = "https://files.pythonhosted.org/packages/26/4d/e784ce93431518fdb1c790afcddb0159fb1731c30855869396c575905f5b/randomgen-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ebbc9fc43c9142e1e9a02a7a0d19adf6c7092dce4456f3ee07706432da6529fc", size = 3472494 }, 519 | { url = "https://files.pythonhosted.org/packages/70/17/a692a83f0d2cf137f3e205780d549322c716720cf3e31258a6aa9689954f/randomgen-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b0adb770932185fccabdd25e3428e6798399ab70871da0f8adcfc2656cbded81", size = 3378070 }, 520 | { url = "https://files.pythonhosted.org/packages/88/29/c87613e6bae921e21b3aa0025b47eed31bfef6f71a2021c73c2a1bc36ec5/randomgen-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03a8df871ac9bade6e570d5a6aa05823bcc25a8aea23394e2bc090cf388b1862", size = 3603619 }, 521 | { url = "https://files.pythonhosted.org/packages/8d/09/e17de8f4215f52525da09b8269fc2cee1095c1a75ac4d141562217defaa2/randomgen-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ec3a57faa6ebe0eff7baa5d1c462472702adefc93721bee971b8d490c8d38e3", size = 3714680 }, 522 | { url = "https://files.pythonhosted.org/packages/0c/d3/da0a692ca4d11f4874e669d9550f6828d83785e34ab75e3f599cc6073eba/randomgen-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5d350c48aabb0245a14da5e33352aed8d11f5911b11668c737b049be8b441228", size = 3758955 }, 523 | { url = "https://files.pythonhosted.org/packages/07/c0/6ff955414293af5229d0cf41f0cbefc6c7bc827cf9865f3cf655fcfbce80/randomgen-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:cc54b61e845b41692b114c7e3dacf2305cc91b98af18a32b5ca2f706c476985a", size = 6702160 }, 524 | { url = "https://files.pythonhosted.org/packages/8e/4a/1e0074ee9fe0ddeced394019cea140e5b1a4257cd569e8363d210bbf20aa/randomgen-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:05cb0c68f1a4db9099f2f82c25725fbdd18e8dd7891f6241b247243f431693b3", size = 3473640 }, 525 | { url = "https://files.pythonhosted.org/packages/04/46/ecd8a21b1ed3deb91c9e81bfd84915adddcace91a4ac44a051031497f9c9/randomgen-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c467d3a2bfd863b9853a49b07b9e03e432084bef3a1a0d59259d31134509788", size = 3377911 }, 526 | { url = "https://files.pythonhosted.org/packages/b1/d4/b199266de7b219f3ec34831f8b7b033df6b3349584e8caa84e8165ff3fb5/randomgen-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c5a8f147bf3b6f68b4fadf8fe0a9b46c7c0e9c9f474aa194b8db0886677c11f", size = 3604412 }, 527 | { url = "https://files.pythonhosted.org/packages/11/09/637333df7d27c2f28f72efcf23cb4adf94c2f7231f3e3735f9d57455ef99/randomgen-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61b5794658c9a51b6ea5a2fecbb91bcfae142551867e295f8a267e2d6b5bf859", size = 3713873 }, 528 | { url = "https://files.pythonhosted.org/packages/23/ce/863e4bfe5500be1a1c0df35594830bd589e870d3f24d3a6b8c49eb98d3ff/randomgen-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:652e7913c01212c426cc3230518743dc4e838c8cef4659a2ff0b6427cc11d89b", size = 3760597 }, 529 | { url = "https://files.pythonhosted.org/packages/d4/37/598eeca7bf543a787460babfd389aaaba3bb5fac500d70eb0b925dc27376/randomgen-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:36f91eff5d6e0c1b66cf11a8eb0b097002dd692c4838ae7d35e9051f6cd1613b", size = 6706753 }, 530 | { url = "https://files.pythonhosted.org/packages/30/b6/78cb9d6d8c8bb134b780be5eba98ed8853eda9906445e0cc1c7b977e43d1/randomgen-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d97f254c7eac9c92be87cf3c208e5a64304cbcdef08169d3f120461315bd76ef", size = 3464314 }, 531 | { url = "https://files.pythonhosted.org/packages/5d/4c/e0fc9a12c5fa4a85c099f1e643dfa068f62844c09ed80c1a0f36d214b3b0/randomgen-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0085fc33c9ca1ed16d67b37e5686b8fa51422656bccb0cc903367a1bdc931bc", size = 3374570 }, 532 | { url = "https://files.pythonhosted.org/packages/41/c7/e68b85efb8e3746d0b9266121cb2bb19d28f83080b43c43c9a86b4629281/randomgen-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fe2f91e59436c138c83da108b50bf9109c256d9e0b16403a112eda2fc20c469", size = 3558723 }, 533 | { url = "https://files.pythonhosted.org/packages/c3/05/d083ff3e861852e01079fc33ab85117b138b6a423ace6e7bd2ec269d5f67/randomgen-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a02b77218ae7a7b3df8938a0ecd7f0cfe22993b2caf05f7cabbb5fe38e38d0f", size = 3666979 }, 534 | { url = "https://files.pythonhosted.org/packages/26/60/3ae416c7245853fbc2081368104f1dafc66fa87d4fcccebc62403f9c047e/randomgen-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:440749d99fca2df7ac72cfde6fe310e7ed123530ad2a3f8a4cd05c1354b6fb51", size = 3706012 }, 535 | { url = "https://files.pythonhosted.org/packages/92/ea/a502b9e5fdcdf58af4a19bb9ae386201784ab7f60845db1b6f76d3b5a556/randomgen-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:9c641e1c36a5e3504a5e2ae539689636a827b89acec2d8b60526e5351b5807b6", size = 6686115 }, 536 | { url = "https://files.pythonhosted.org/packages/03/92/5470a57a5224439c1f058fd3d1929afc257c40572e55b9b6ba8ca284e5b8/randomgen-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a904bc3593b5f448fb286c44f9b1269b67f82d53cc9131dfd75fe3283f592b55", size = 3424002 }, 537 | { url = "https://files.pythonhosted.org/packages/6a/e1/a5db43bb45751a29573ff677728b47848efb99c76f580488cd9d06f28d3f/randomgen-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3ee2916e3faebdf2637c6acf533e4bae6bb8e86bed4ecca294e2f7104dfac63e", size = 3338716 }, 538 | { url = "https://files.pythonhosted.org/packages/cd/64/1fdef87ac27b0c39200fc716858c800525b7b8f3d9b2e56645ddff480294/randomgen-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378fe12392dc03c1274a52d874bc915f9427b75dbd6f884577fd92fe91059652", size = 3537451 }, 539 | { url = "https://files.pythonhosted.org/packages/55/ac/b09d673970010db1e508220896e6125bf7cc873736054f49b44d4e6e5cb3/randomgen-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63a40c6aba83276950f02b7f8619a24ecef68065fe468950583495e18de86678", size = 3645896 }, 540 | { url = "https://files.pythonhosted.org/packages/2e/d9/76d116cba7f48f29bee755394ca88451fd5cab2f7211f603c9a9c0ae02dd/randomgen-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d4b561ba826c159f450e2dbe422bf4043e619552d49192bb2bf556538b61c24", size = 3689308 }, 541 | { url = "https://files.pythonhosted.org/packages/a4/ae/89dddf238e5ccdc3b600b169654328d6765f05156ba94fde9d0788d66474/randomgen-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:7d63859f3bf841d54d698b30267a9f2b5663c1bf5b8439d5a18188ed361a0842", size = 6669647 }, 542 | { url = "https://files.pythonhosted.org/packages/7b/d6/e0ab46d0757f6976a1145763c4412433175c9be9a0e77980ca47b25906dd/randomgen-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4972db5e3f167e0362dd8cfc77e3038d27f548a136daa1cf9abbec638206c4e9", size = 3490199 }, 543 | { url = "https://files.pythonhosted.org/packages/fa/a9/5d2356d4a6d7fcfad4cc17f563d228b1ddd9076c09dd29541139a832b72b/randomgen-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1dd8394bab0c6d97e082b93895e541052020ffe70d0494e59f23198ae6d95b4", size = 3393940 }, 544 | { url = "https://files.pythonhosted.org/packages/71/fa/9c071f1c800afbc94e562570fb1b4f22a52a24702e950139c0c377dc4b29/randomgen-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97213521a6408d42843112170f7aa66645fd6688a1e5e7d574383dac92bdffbd", size = 3618500 }, 545 | { url = "https://files.pythonhosted.org/packages/7a/e2/7169a6cfa2c6e45481e54714d4304693ab434ca253deb7816b26c4be5f39/randomgen-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2b3877a988ce7a8e3422e0d6bf42f69cad990fc52365b36db26527a78b6fc1a", size = 3728279 }, 546 | { url = "https://files.pythonhosted.org/packages/64/99/5bb82487107d845951f5fb9bc449287110b12dbc5a0846d4d086fb526f6e/randomgen-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:f27922497aa27ef7a843a51ed19c5c9ef27a3ef69c2f4a62bf05c89f26edad0b", size = 6717080 }, 547 | ] 548 | 549 | [[package]] 550 | name = "requests" 551 | version = "2.32.3" 552 | source = { registry = "https://pypi.org/simple" } 553 | dependencies = [ 554 | { name = "certifi" }, 555 | { name = "charset-normalizer" }, 556 | { name = "idna" }, 557 | { name = "urllib3" }, 558 | ] 559 | sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } 560 | wheels = [ 561 | { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, 562 | ] 563 | 564 | [[package]] 565 | name = "responses" 566 | version = "0.25.3" 567 | source = { registry = "https://pypi.org/simple" } 568 | dependencies = [ 569 | { name = "pyyaml" }, 570 | { name = "requests" }, 571 | { name = "urllib3" }, 572 | ] 573 | sdist = { url = "https://files.pythonhosted.org/packages/67/24/1d67c8974daa502e860b4a5b57ad6de0d7dbc0b1160ef7148189a24a40e1/responses-0.25.3.tar.gz", hash = "sha256:617b9247abd9ae28313d57a75880422d55ec63c29d33d629697590a034358dba", size = 77798 } 574 | wheels = [ 575 | { url = "https://files.pythonhosted.org/packages/12/24/93293d0be0db9da1ed8dfc5e6af700fdd40e8f10a928704dd179db9f03c1/responses-0.25.3-py3-none-any.whl", hash = "sha256:521efcbc82081ab8daa588e08f7e8a64ce79b91c39f6e62199b19159bea7dbcb", size = 55238 }, 576 | ] 577 | 578 | [[package]] 579 | name = "tomli" 580 | version = "2.1.0" 581 | source = { registry = "https://pypi.org/simple" } 582 | sdist = { url = "https://files.pythonhosted.org/packages/1e/e4/1b6cbcc82d8832dd0ce34767d5c560df8a3547ad8cbc427f34601415930a/tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8", size = 16622 } 583 | wheels = [ 584 | { url = "https://files.pythonhosted.org/packages/de/f7/4da0ffe1892122c9ea096c57f64c2753ae5dd3ce85488802d11b0992cc6d/tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391", size = 13750 }, 585 | ] 586 | 587 | [[package]] 588 | name = "typing-extensions" 589 | version = "4.12.2" 590 | source = { registry = "https://pypi.org/simple" } 591 | sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } 592 | wheels = [ 593 | { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, 594 | ] 595 | 596 | [[package]] 597 | name = "urllib3" 598 | version = "2.2.3" 599 | source = { registry = "https://pypi.org/simple" } 600 | sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } 601 | wheels = [ 602 | { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, 603 | ] 604 | 605 | [[package]] 606 | name = "xdg" 607 | version = "6.0.0" 608 | source = { registry = "https://pypi.org/simple" } 609 | sdist = { url = "https://files.pythonhosted.org/packages/2a/b9/0e6e6f19fb75cf5e1758f4f33c1256738f718966700cffc0fde2f966218b/xdg-6.0.0.tar.gz", hash = "sha256:24278094f2d45e846d1eb28a2ebb92d7b67fc0cab5249ee3ce88c95f649a1c92", size = 3453 } 610 | wheels = [ 611 | { url = "https://files.pythonhosted.org/packages/dd/54/3516c1cf349060fc3578686d271eba242f10ec00b4530c2985af9faac49b/xdg-6.0.0-py3-none-any.whl", hash = "sha256:df3510755b4395157fc04fc3b02467c777f3b3ca383257397f09ab0d4c16f936", size = 3855 }, 612 | ] 613 | --------------------------------------------------------------------------------