├── tests ├── __init__.py └── test_pytest_randomly.py ├── src └── pytest_randomly │ ├── py.typed │ └── __init__.py ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature-request.yml │ └── issue.yml ├── SECURITY.md ├── CODE_OF_CONDUCT.md ├── dependabot.yml └── workflows │ └── main.yml ├── HISTORY.rst ├── .gitignore ├── MANIFEST.in ├── .editorconfig ├── .typos.toml ├── tox.ini ├── LICENSE ├── .pre-commit-config.yaml ├── pyproject.toml ├── README.rst ├── CHANGELOG.rst └── uv.lock /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pytest_randomly/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | Please report security issues directly over email to me@adamj.eu 2 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | See https://github.com/pytest-dev/pytest-randomly/blob/main/CHANGELOG.rst 2 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | This project follows [Django's Code of Conduct](https://www.djangoproject.com/conduct/). 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info/ 2 | *.pyc 3 | /.coverage 4 | /.coverage.* 5 | /.tox 6 | /build/ 7 | /dist/ 8 | /docs/_build/ 9 | /example/.venv/ 10 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | prune tests 2 | include CHANGELOG.rst 3 | include LICENSE 4 | include logo.png 5 | include pyproject.toml 6 | include README.rst 7 | include src/*/py.typed 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | groups: 6 | "GitHub Actions": 7 | patterns: 8 | - "*" 9 | schedule: 10 | interval: monthly 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.py] 14 | indent_size = 4 15 | 16 | [Makefile] 17 | indent_style = tab 18 | -------------------------------------------------------------------------------- /.typos.toml: -------------------------------------------------------------------------------- 1 | # Configuration file for 'typos' tool 2 | # https://github.com/crate-ci/typos 3 | 4 | [default] 5 | extend-ignore-re = [ 6 | # Single line ignore comments 7 | "(?Rm)^.*(#|//)\\s*typos: ignore$", 8 | # Multi-line ignore comments 9 | "(?s)(#|//)\\s*typos: off.*?\\n\\s*(#|//)\\s*typos: on" 10 | ] 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Request an enhancement or new feature. 3 | body: 4 | - type: textarea 5 | id: description 6 | attributes: 7 | label: Description 8 | description: Please describe your feature request with appropriate detail. 9 | validations: 10 | required: true 11 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | requires = 3 | tox>=4.2 4 | env_list = 5 | py{314, 313, 312, 311, 310} 6 | 7 | [testenv] 8 | runner = uv-venv-lock-runner 9 | package = wheel 10 | wheel_build_env = .pkg 11 | set_env = 12 | PYTHONDEVMODE = 1 13 | commands = 14 | python \ 15 | -W error::ResourceWarning \ 16 | -W error::DeprecationWarning \ 17 | -W error::PendingDeprecationWarning \ 18 | -W ignore:'pkg_resources is deprecated as an API':DeprecationWarning \ 19 | -W ignore:'datetime.datetime.utcfromtimestamp() is deprecated':DeprecationWarning \ 20 | -m coverage run \ 21 | -m pytest -p no:randomly {posargs:tests} 22 | dependency_groups = 23 | test 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.yml: -------------------------------------------------------------------------------- 1 | name: Issue 2 | description: File an issue 3 | body: 4 | - type: input 5 | id: python_version 6 | attributes: 7 | label: Python Version 8 | description: Which version of Python were you using? 9 | placeholder: 3.14.0 10 | validations: 11 | required: false 12 | - type: input 13 | id: pytest_version 14 | attributes: 15 | label: pytest Version 16 | description: Which version of pytest were you using? 17 | placeholder: 6.2.4 18 | validations: 19 | required: false 20 | - type: input 21 | id: package_version 22 | attributes: 23 | label: Package Version 24 | description: Which version of this package were you using? If not the latest version, please check this issue has not since been resolved. 25 | placeholder: 1.0.0 26 | validations: 27 | required: false 28 | - type: textarea 29 | id: description 30 | attributes: 31 | label: Description 32 | description: Please describe your issue. 33 | validations: 34 | required: true 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Adam Johnson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | ci: 2 | autoupdate_schedule: monthly 3 | 4 | default_language_version: 5 | python: python3.13 6 | 7 | repos: 8 | - repo: https://github.com/pre-commit/pre-commit-hooks 9 | rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 10 | hooks: 11 | - id: check-added-large-files 12 | - id: check-case-conflict 13 | - id: check-json 14 | - id: check-merge-conflict 15 | - id: check-symlinks 16 | - id: check-toml 17 | - id: end-of-file-fixer 18 | - id: trailing-whitespace 19 | - repo: https://github.com/crate-ci/typos 20 | rev: 802d5794ff9cf7b15610c47eca99cd1ab757d8d4 # frozen: v1 21 | hooks: 22 | - id: typos 23 | - repo: https://github.com/tox-dev/pyproject-fmt 24 | rev: d252a2a7678b47d1f2eea2f6b846ddfdcd012759 # frozen: v2.11.1 25 | hooks: 26 | - id: pyproject-fmt 27 | - repo: https://github.com/tox-dev/tox-ini-fmt 28 | rev: be26ee0d710a48f7c1acc1291d84082036207bd3 # frozen: 1.7.0 29 | hooks: 30 | - id: tox-ini-fmt 31 | - repo: https://github.com/rstcheck/rstcheck 32 | rev: 27258fde1ee7d3b1e6a7bbc58f4c7b1dd0e719e5 # frozen: v6.2.5 33 | hooks: 34 | - id: rstcheck 35 | additional_dependencies: 36 | - tomli==2.0.1 37 | - repo: https://github.com/adamchainz/blacken-docs 38 | rev: dda8db18cfc68df532abf33b185ecd12d5b7b326 # frozen: 1.20.0 39 | hooks: 40 | - id: blacken-docs 41 | additional_dependencies: 42 | - black==25.1.0 43 | - repo: https://github.com/astral-sh/ruff-pre-commit 44 | rev: 36243b70e5ce219623c3503f5afba0f8c96fda55 # frozen: v0.14.7 45 | hooks: 46 | - id: ruff-check 47 | args: [ --fix ] 48 | - id: ruff-format 49 | - repo: https://github.com/pre-commit/mirrors-mypy 50 | rev: c2738302f5cf2bfb559c1f210950badb133613ea # frozen: v1.19.0 51 | hooks: 52 | - id: mypy 53 | additional_dependencies: 54 | - pytest==7.4.2 55 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - '**' 9 | pull_request: 10 | 11 | concurrency: 12 | group: ${{ github.head_ref || github.run_id }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | tests: 17 | name: Python ${{ matrix.python-version }} 18 | runs-on: ubuntu-24.04 19 | 20 | strategy: 21 | matrix: 22 | python-version: 23 | - '3.10' 24 | - '3.11' 25 | - '3.12' 26 | - '3.13' 27 | - '3.14' 28 | 29 | steps: 30 | - uses: actions/checkout@v6 31 | 32 | - uses: actions/setup-python@v6 33 | with: 34 | python-version: ${{ matrix.python-version }} 35 | allow-prereleases: true 36 | 37 | - name: Install uv 38 | uses: astral-sh/setup-uv@v7 39 | with: 40 | enable-cache: true 41 | 42 | - name: Run tox targets for ${{ matrix.python-version }} 43 | run: uvx --with tox-uv tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) 44 | 45 | - name: Upload coverage data 46 | uses: actions/upload-artifact@v5 47 | with: 48 | name: coverage-data-${{ matrix.python-version }} 49 | path: '${{ github.workspace }}/.coverage.*' 50 | include-hidden-files: true 51 | if-no-files-found: error 52 | 53 | coverage: 54 | name: Coverage 55 | runs-on: ubuntu-24.04 56 | needs: tests 57 | steps: 58 | - uses: actions/checkout@v6 59 | 60 | - uses: actions/setup-python@v6 61 | with: 62 | python-version: '3.13' 63 | 64 | - name: Install uv 65 | uses: astral-sh/setup-uv@v7 66 | 67 | - name: Install dependencies 68 | run: uv pip install --system coverage[toml] 69 | 70 | - name: Download data 71 | uses: actions/download-artifact@v6 72 | with: 73 | path: ${{ github.workspace }} 74 | pattern: coverage-data-* 75 | merge-multiple: true 76 | 77 | - name: Combine coverage and fail if it's <100% 78 | run: | 79 | python -m coverage combine 80 | python -m coverage html --skip-covered --skip-empty 81 | python -m coverage report --fail-under=100 82 | echo "## Coverage summary" >> $GITHUB_STEP_SUMMARY 83 | python -m coverage report --format=markdown >> $GITHUB_STEP_SUMMARY 84 | 85 | - name: Upload HTML report 86 | if: ${{ failure() }} 87 | uses: actions/upload-artifact@v5 88 | with: 89 | name: html-report 90 | path: htmlcov 91 | 92 | release: 93 | needs: [coverage] 94 | if: success() && startsWith(github.ref, 'refs/tags/') 95 | runs-on: ubuntu-24.04 96 | environment: release 97 | 98 | permissions: 99 | contents: read 100 | id-token: write 101 | 102 | steps: 103 | - uses: actions/checkout@v6 104 | 105 | - uses: astral-sh/setup-uv@v7 106 | 107 | - name: Build 108 | run: uv build 109 | 110 | - uses: pypa/gh-action-pypi-publish@release/v1 111 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | build-backend = "setuptools.build_meta" 3 | requires = [ 4 | "setuptools>=77", 5 | ] 6 | 7 | [project] 8 | name = "pytest-randomly" 9 | version = "4.0.1" 10 | description = "Pytest plugin to randomly order tests and control random.seed." 11 | readme = "README.rst" 12 | keywords = [ 13 | "pytest", 14 | "random", 15 | "randomise", 16 | "randomize", 17 | "randomly", 18 | ] 19 | license = "MIT" 20 | license-files = [ "LICENSE" ] 21 | authors = [ 22 | { name = "Adam Johnson", email = "me@adamj.eu" }, 23 | ] 24 | requires-python = ">=3.10" 25 | classifiers = [ 26 | "Development Status :: 5 - Production/Stable", 27 | "Framework :: Pytest", 28 | "Intended Audience :: Developers", 29 | "Natural Language :: English", 30 | "Programming Language :: Python :: 3 :: Only", 31 | "Programming Language :: Python :: 3.10", 32 | "Programming Language :: Python :: 3.11", 33 | "Programming Language :: Python :: 3.12", 34 | "Programming Language :: Python :: 3.13", 35 | "Programming Language :: Python :: 3.14", 36 | "Typing :: Typed", 37 | ] 38 | dependencies = [ 39 | "pytest", 40 | ] 41 | urls.Changelog = "https://github.com/pytest-dev/pytest-randomly/blob/main/CHANGELOG.rst" 42 | urls.Funding = "https://adamj.eu/books/" 43 | urls.Repository = "https://github.com/pytest-dev/pytest-randomly" 44 | entry-points.pytest11.randomly = "pytest_randomly" 45 | 46 | [dependency-groups] 47 | test = [ 48 | "coverage[toml]", 49 | "factory-boy", 50 | "faker", 51 | "model-bakery>=1.13", 52 | "numpy", 53 | "pytest", 54 | "pytest-xdist", 55 | ] 56 | 57 | [tool.ruff] 58 | lint.select = [ 59 | # flake8-bugbear 60 | "B", 61 | # flake8-comprehensions 62 | "C4", 63 | # pycodestyle 64 | "E", 65 | # Pyflakes errors 66 | "F", 67 | # isort 68 | "I", 69 | # flake8-simplify 70 | "SIM", 71 | # flake8-tidy-imports 72 | "TID", 73 | # pyupgrade 74 | "UP", 75 | # Pyflakes warnings 76 | "W", 77 | ] 78 | lint.ignore = [ 79 | # flake8-bugbear opinionated rules 80 | "B9", 81 | # line-too-long 82 | "E501", 83 | # suppressible-exception 84 | "SIM105", 85 | # if-else-block-instead-of-if-exp 86 | "SIM108", 87 | ] 88 | lint.extend-safe-fixes = [ 89 | # non-pep585-annotation 90 | "UP006", 91 | ] 92 | lint.isort.required-imports = [ "from __future__ import annotations" ] 93 | 94 | [tool.pyproject-fmt] 95 | max_supported_python = "3.14" 96 | 97 | [tool.pytest.ini_options] 98 | addopts = """\ 99 | --strict-config 100 | --strict-markers 101 | """ 102 | xfail_strict = true 103 | 104 | [tool.coverage.run] 105 | branch = true 106 | parallel = true 107 | source = [ 108 | "pytest_randomly", 109 | "tests", 110 | ] 111 | 112 | [tool.coverage.paths] 113 | source = [ 114 | "src", 115 | ".tox/**/site-packages", 116 | ] 117 | 118 | [tool.coverage.report] 119 | show_missing = true 120 | 121 | [tool.mypy] 122 | enable_error_code = [ 123 | "ignore-without-code", 124 | "redundant-expr", 125 | "truthy-bool", 126 | ] 127 | mypy_path = "src/" 128 | namespace_packages = false 129 | strict = true 130 | warn_unreachable = true 131 | 132 | [[tool.mypy.overrides]] 133 | module = "tests.*" 134 | allow_untyped_defs = true 135 | 136 | [tool.rstcheck] 137 | report_level = "ERROR" 138 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | pytest-randomly 3 | =============== 4 | 5 | .. image:: https://img.shields.io/github/actions/workflow/status/pytest-dev/pytest-randomly/main.yml.svg?branch=main&style=for-the-badge 6 | :target: https://github.com/pytest-dev/pytest-randomly/actions?workflow=CI 7 | 8 | .. image:: https://img.shields.io/badge/Coverage-100%25-success?style=for-the-badge 9 | :target: https://github.com/pytest-dev/pytest-randomly/actions?workflow=CI 10 | 11 | .. image:: https://img.shields.io/pypi/v/pytest-randomly.svg?style=for-the-badge 12 | :target: https://pypi.org/project/pytest-randomly/ 13 | 14 | .. image:: https://img.shields.io/badge/code%20style-black-000000.svg?style=for-the-badge 15 | :target: https://github.com/psf/black 16 | 17 | .. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=for-the-badge 18 | :target: https://github.com/pre-commit/pre-commit 19 | :alt: pre-commit 20 | 21 | Pytest plugin to randomly order tests and control ``random.seed``. 22 | 23 | ---- 24 | 25 | **Testing a Django project?** 26 | Check out my book `Speed Up Your Django Tests `__ which covers loads of ways to write faster, more accurate tests. 27 | 28 | ---- 29 | 30 | Features 31 | ======== 32 | 33 | All of these features are on by default but can be disabled with flags. 34 | 35 | * Randomly shuffles the order of test items. This is done first at the level of 36 | modules, then at the level of test classes (if you have them), then at the 37 | order of functions. This also works with things like doctests. 38 | 39 | * Generates a base random seed or accepts one for reproduction with ``--randomly-seed``. 40 | The base random seed is printed at the start of the test run, and can be passed in to repeat a failure caused by test ordering or random data. 41 | 42 | * At the start of the test run, and before each test setup, run, and teardown, it resets Python’s global random seed to a fixed value, using |random.seed()|__. 43 | The fixed value is derived from the base random seed, the pytest test ID, and an offset for setup or teardown. 44 | This ensures each test gets a different but repeatable random seed. 45 | 46 | .. |random.seed()| replace:: ``random.seed()`` 47 | __ https://docs.python.org/3/library/random.html#random.seed 48 | 49 | * pytest-randomly also resets several libraries’ random states at the start of 50 | every test, if they are installed: 51 | 52 | * `factory boy `__ 53 | 54 | * `Faker `__ 55 | 56 | The ``faker`` pytest fixture is also affected, as pytest-randomly defines |the faker_seed fixture|__. 57 | 58 | .. |the faker_seed fixture| replace:: the ``faker_seed`` fixture 59 | __ https://faker.readthedocs.io/en/master/pytest-fixtures.html#seeding-configuration 60 | 61 | * `Model Bakery `__ 62 | 63 | * `NumPy `_ 64 | 65 | Only its `legacy random state `__ is affected. 66 | 67 | * If additional random generators are used, they can be registered under the 68 | ``pytest_randomly.random_seeder`` 69 | `entry point `_ and 70 | will have their seed reset at the start of every test. Register a function 71 | that takes the current seed value. 72 | 73 | * Works with `pytest-xdist `__. 74 | 75 | About 76 | ===== 77 | 78 | Randomness in testing can be quite powerful to discover hidden flaws in the 79 | tests themselves, as well as giving a little more coverage to your system. 80 | 81 | By randomly ordering the tests, the risk of surprising inter-test dependencies 82 | is reduced - a technique used in many places, for example Google's C++ test 83 | runner `googletest 84 | `_. 85 | Research suggests that "dependent tests do exist in practice" and a random 86 | order of test executions can effectively detect such dependencies [1]_. 87 | Alternatively, a reverse order of test executions, as provided by `pytest-reverse 88 | `__, may find less dependent 89 | tests but can achieve a better benefit/cost ratio. 90 | 91 | By resetting the random seed to a repeatable number for each test, tests can 92 | create data based on random numbers and yet remain repeatable, for example 93 | factory boy's fuzzy values. This is good for ensuring that tests specify the 94 | data they need and that the tested system is not affected by any data that is 95 | filled in randomly due to not being specified. 96 | 97 | I have written a `blog post covering the history of 98 | pytest-randomly `__, 99 | including how it started life as the nose plugin 100 | `nose-randomly `__. 101 | 102 | Additionally, I appeared on the Test and Code podcast to `talk about 103 | pytest-randomly `__. 104 | 105 | Installation 106 | ============ 107 | 108 | Install with: 109 | 110 | .. code-block:: bash 111 | 112 | python -m pip install pytest-randomly 113 | 114 | Python 3.10 to 3.14 supported. 115 | 116 | Usage 117 | ===== 118 | 119 | Pytest will automatically find the plugin and use it when you run ``pytest``. 120 | The output will start with an extra line that tells you the random seed that is 121 | being used: 122 | 123 | .. code-block:: bash 124 | 125 | $ pytest 126 | ... 127 | platform darwin -- Python ... 128 | Using --randomly-seed=1553614239 129 | ... 130 | 131 | If the tests fail due to ordering or randomly created data, you can restart 132 | them with that seed using the flag as suggested: 133 | 134 | .. code-block:: bash 135 | 136 | pytest --randomly-seed=1234 137 | 138 | Or more conveniently, use the special value ``last``: 139 | 140 | .. code-block:: bash 141 | 142 | pytest --randomly-seed=last 143 | 144 | (This only works if pytest’s cacheprovider plugin has not been disabled.) 145 | 146 | Since the ordering is by module, then by class, you can debug inter-test 147 | pollution failures by narrowing down which tests are being run to find the bad 148 | interaction by rerunning just the module/class: 149 | 150 | .. code-block:: bash 151 | 152 | pytest --randomly-seed=1234 tests/module_that_failed/ 153 | 154 | You can disable behaviours you don't like with the following flags: 155 | 156 | * ``--randomly-dont-reset-seed`` - turn off the reset of ``random.seed()`` at 157 | the start of every test 158 | * ``--randomly-dont-reorganize`` - turn off the shuffling of the order of tests 159 | 160 | The plugin appears to Pytest with the name 'randomly'. To disable it 161 | altogether, you can use the ``-p`` argument, for example: 162 | 163 | .. code-block:: sh 164 | 165 | pytest -p no:randomly 166 | 167 | Avoid reordering some tests 168 | --------------------------- 169 | 170 | To fix the order of some tests, use the ``pytest-order`` plugin. 171 | See its `documentation section `__ on usage with pytest-randomly. 172 | 173 | Entry Point 174 | =========== 175 | 176 | If you're using a different randomness generator in your third party package, 177 | you can register an entrypoint to be called every time ``pytest-randomly`` 178 | reseeds. Implement the entrypoint ``pytest_randomly.random_seeder``, referring 179 | to a function/callable that takes one argument, the new seed (int). 180 | 181 | For example in your ``setup.cfg``: 182 | 183 | .. code-block:: ini 184 | 185 | [options.entry_points] 186 | pytest_randomly.random_seeder = 187 | mypackage = mypackage.reseed 188 | 189 | Then implement ``reseed(new_seed)``. 190 | 191 | References 192 | ========== 193 | 194 | .. [1] Sai Zhang, Darioush Jalali, Jochen Wuttke, Kıvanç Muşlu, Wing Lam, Michael D. Ernst, and David Notkin. 2014. Empirically revisiting the test independence assumption. In Proceedings of the 2014 International Symposium on Software Testing and Analysis (ISSTA 2014). Association for Computing Machinery, New York, NY, USA, 385–396. doi:https://doi.org/10.1145/2610384.2610404 195 | -------------------------------------------------------------------------------- /src/pytest_randomly/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import argparse 4 | import random 5 | from collections.abc import Callable 6 | from functools import lru_cache 7 | from importlib.metadata import entry_points 8 | from itertools import groupby 9 | from types import ModuleType 10 | from typing import Any, TypeVar 11 | from zlib import crc32 12 | 13 | from _pytest.config import Config 14 | from _pytest.config.argparsing import Parser 15 | from _pytest.fixtures import SubRequest 16 | from _pytest.nodes import Item 17 | from pytest import Collector, fixture, hookimpl 18 | 19 | # factory-boy 20 | try: 21 | from factory.random import set_random_state as factory_set_random_state 22 | 23 | have_factory_boy = True 24 | except ImportError: # pragma: no cover 25 | # old versions 26 | try: 27 | from factory.fuzzy import set_random_state as factory_set_random_state 28 | 29 | have_factory_boy = True 30 | except ImportError: 31 | have_factory_boy = False 32 | 33 | # faker 34 | try: 35 | from faker.generator import random as faker_random 36 | 37 | have_faker = True 38 | except ImportError: # pragma: no cover 39 | have_faker = False 40 | 41 | # model_bakery 42 | try: 43 | from model_bakery.random_gen import baker_random 44 | 45 | have_model_bakery = True 46 | except ImportError: # pragma: no cover 47 | have_model_bakery = False 48 | 49 | # numpy 50 | try: 51 | from numpy import random as np_random 52 | 53 | have_numpy = True 54 | except ImportError: # pragma: no cover 55 | have_numpy = False 56 | 57 | 58 | def make_seed() -> int: 59 | return random.Random().getrandbits(32) 60 | 61 | 62 | def seed_type(string: str) -> str | int: 63 | if string in ("default", "last"): 64 | return string 65 | try: 66 | return int(string) 67 | except ValueError: 68 | raise argparse.ArgumentTypeError( 69 | f"{repr(string)} is not an integer or the string 'last'" 70 | ) 71 | 72 | 73 | def pytest_addoption(parser: Parser) -> None: 74 | group = parser.getgroup("randomly", "pytest-randomly") 75 | group._addoption( 76 | "--randomly-seed", 77 | action="store", 78 | dest="randomly_seed", 79 | default="default", 80 | type=seed_type, 81 | help="""Set the seed that pytest-randomly uses (int), or pass the 82 | special value 'last' to reuse the seed from the previous run. 83 | Default behaviour: use random.Random().getrandbits(32), so the seed is 84 | different on each run.""", 85 | ) 86 | group._addoption( 87 | "--randomly-dont-reset-seed", 88 | action="store_false", 89 | dest="randomly_reset_seed", 90 | default=True, 91 | help="""Stop pytest-randomly from resetting random.seed() at the 92 | start of every test context (e.g. TestCase) and individual 93 | test.""", 94 | ) 95 | group._addoption( 96 | "--randomly-dont-reorganize", 97 | action="store_false", 98 | dest="randomly_reorganize", 99 | default=True, 100 | help="Stop pytest-randomly from randomly reorganizing the test order.", 101 | ) 102 | 103 | 104 | def pytest_configure(config: Config) -> None: 105 | if config.pluginmanager.hasplugin("xdist"): 106 | config.pluginmanager.register(XdistHooks()) 107 | 108 | seed_value = config.getoption("randomly_seed") 109 | if seed_value == "last": 110 | assert hasattr(config, "cache"), ( 111 | "The cacheprovider plugin is required to use 'last'" 112 | ) 113 | assert config.cache is not None 114 | seed = config.cache.get("randomly_seed", make_seed()) 115 | elif seed_value == "default": 116 | if hasattr(config, "workerinput"): # pragma: no cover 117 | # pytest-xdist: use seed generated on main. 118 | seed = config.workerinput["randomly_seed"] 119 | else: 120 | seed = make_seed() 121 | else: 122 | seed = seed_value 123 | if hasattr(config, "cache"): 124 | assert config.cache is not None 125 | config.cache.set("randomly_seed", seed) 126 | config.option.randomly_seed = seed 127 | 128 | 129 | class XdistHooks: 130 | # Hooks for xdist only, registered when needed in pytest_configure() 131 | # https://docs.pytest.org/en/latest/writing_plugins.html#optionally-using-hooks-from-3rd-party-plugins # noqa: E501 132 | 133 | def pytest_configure_node(self, node: Item) -> None: 134 | seed = node.config.getoption("randomly_seed") 135 | node.workerinput["randomly_seed"] = seed # type: ignore [attr-defined] 136 | 137 | 138 | entrypoint_reseeds: list[Callable[[int], None]] | None = None 139 | 140 | 141 | def _reseed(config: Config, offset: int = 0) -> int: 142 | global entrypoint_reseeds 143 | seed: int = config.getoption("randomly_seed") + offset 144 | 145 | random.seed(seed) 146 | random_state = random.getstate() 147 | 148 | if have_factory_boy: # pragma: no branch 149 | factory_set_random_state(random_state) 150 | 151 | if have_faker: # pragma: no branch 152 | faker_random.setstate(random_state) 153 | 154 | if have_model_bakery: # pragma: no branch 155 | baker_random.setstate(random_state) 156 | 157 | if have_numpy: # pragma: no branch 158 | np_random.seed(seed % 2**32) 159 | 160 | if entrypoint_reseeds is None: 161 | eps = entry_points(group="pytest_randomly.random_seeder") 162 | entrypoint_reseeds = [e.load() for e in eps] 163 | for reseed in entrypoint_reseeds: 164 | reseed(seed) 165 | 166 | return seed 167 | 168 | 169 | def pytest_report_header(config: Config) -> str: 170 | seed = config.getoption("randomly_seed") 171 | _reseed(config) 172 | return f"Using --randomly-seed={seed}" 173 | 174 | 175 | def pytest_runtest_setup(item: Item) -> None: 176 | if item.config.getoption("randomly_reset_seed"): 177 | _reseed(item.config, (_crc32(item.nodeid) - 1) % 2**32) 178 | 179 | 180 | def pytest_runtest_call(item: Item) -> None: 181 | if item.config.getoption("randomly_reset_seed"): 182 | _reseed(item.config, _crc32(item.nodeid)) 183 | 184 | 185 | def pytest_runtest_teardown(item: Item) -> None: 186 | if item.config.getoption("randomly_reset_seed"): 187 | _reseed(item.config, (_crc32(item.nodeid) + 1) % 2**32) 188 | 189 | 190 | @hookimpl(tryfirst=True) 191 | def pytest_collection_modifyitems(config: Config, items: list[Item]) -> None: 192 | if not config.getoption("randomly_reorganize"): 193 | return 194 | 195 | seed = _reseed(config) 196 | 197 | modules_items: list[tuple[ModuleType | None, list[Item]]] = [] 198 | for module, group in groupby(items, _get_module): 199 | modules_items.append( 200 | ( 201 | module, 202 | _shuffle_by_class(list(group), seed), 203 | ) 204 | ) 205 | 206 | def _module_key(module_item: tuple[ModuleType | None, list[Item]]) -> int: 207 | module, _items = module_item 208 | if module is None: 209 | return _crc32(f"{seed}::None") 210 | return _crc32(f"{seed}::{module.__name__}") 211 | 212 | modules_items.sort(key=_module_key) 213 | 214 | items[:] = reduce_list_of_lists([subitems for module, subitems in modules_items]) 215 | 216 | 217 | def _get_module(item: Item) -> ModuleType | None: 218 | try: 219 | return getattr(item, "module", None) 220 | except (ImportError, Collector.CollectError): 221 | return None 222 | 223 | 224 | def _shuffle_by_class(items: list[Item], seed: int) -> list[Item]: 225 | klasses_items: list[tuple[type[Any] | None, list[Item]]] = [] 226 | 227 | def _item_key(item: Item) -> int: 228 | return _crc32(f"{seed}::{item.nodeid}") 229 | 230 | for klass, group in groupby(items, _get_cls): 231 | klass_items = list(group) 232 | klass_items.sort(key=_item_key) 233 | klasses_items.append((klass, klass_items)) 234 | 235 | def _cls_key(klass_items: tuple[type[Any] | None, list[Item]]) -> int: 236 | klass, items = klass_items 237 | if klass is None: 238 | return _crc32(f"{seed}::None") 239 | return _crc32(f"{seed}::{klass.__module__}.{klass.__qualname__}") 240 | 241 | klasses_items.sort(key=_cls_key) 242 | 243 | return reduce_list_of_lists([subitems for klass, subitems in klasses_items]) 244 | 245 | 246 | def _get_cls(item: Item) -> type[Any] | None: 247 | return getattr(item, "cls", None) 248 | 249 | 250 | T = TypeVar("T") 251 | 252 | 253 | def reduce_list_of_lists(lists: list[list[T]]) -> list[T]: 254 | new_list = [] 255 | for list_ in lists: 256 | new_list.extend(list_) 257 | return new_list 258 | 259 | 260 | @lru_cache 261 | def _crc32(string: str) -> int: 262 | return crc32(string.encode()) 263 | 264 | 265 | if have_faker: # pragma: no branch 266 | 267 | @fixture(autouse=True) 268 | def faker_seed(pytestconfig: Config, request: SubRequest) -> int: 269 | result: int = pytestconfig.getoption("randomly_seed") + _crc32( 270 | request.node.nodeid 271 | ) 272 | return result 273 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | Changelog 3 | ========= 4 | 5 | * Drop Python 3.9 support. 6 | 7 | 4.0.1 (2025-09-12) 8 | ------------------ 9 | 10 | * Remove the random state caching, which would grow without bound, leaking memory in long test runs. 11 | The caching was added to slightly speed up re-using the same (final) seed, but since the final seed is now different for each test, it has no effect. 12 | 13 | `PR #690 `__. 14 | 15 | * Modify Numpy seed restriction, replacing hashing with a modulo operation. 16 | The extra work to hash is unnecessary now that we generate a final seed per test with CRC32. 17 | This change saves ~500ns per test when Numpy is installed. 18 | 19 | `PR #691 `__. 20 | 21 | 4.0.0 (2025-09-10) 22 | ------------------ 23 | 24 | * Support Python 3.14. 25 | 26 | * Use a different random seed per test, based on the test ID. 27 | 28 | This change should mean that tests exercise more random data values in a given run, and that any randomly-generated identifiers have a lower chance of collision when stored in a shared resource like a database. 29 | 30 | `PR #687 `__. 31 | Thanks to Bryce Drennan for the suggestion in `Issue #600 `__ and initial implementation in `PR #617 `__. 32 | 33 | * Move from MD5 to CRC32 for hashing test IDs, as it’s 5x faster and we don’t need cryptographic security. 34 | 35 | `Issue #686 `__. 36 | 37 | 3.16.0 (2024-10-25) 38 | ------------------- 39 | 40 | * Drop Python 3.8 support. 41 | 42 | * Support Python 3.13. 43 | 44 | 3.15.0 (2023-08-15) 45 | ------------------- 46 | 47 | * Support Python 3.12. 48 | 49 | 3.14.0 (2023-08-15) 50 | ------------------- 51 | 52 | * Reset the random state for `Model Bakery `__. 53 | 54 | 3.13.0 (2023-07-10) 55 | ------------------- 56 | 57 | * Drop Python 3.7 support. 58 | 59 | 3.12.0 (2022-05-11) 60 | ------------------- 61 | 62 | * Support Python 3.11. 63 | 64 | 3.11.0 (2022-01-10) 65 | ------------------- 66 | 67 | * Drop Python 3.6 support. 68 | 69 | 3.10.3 (2021-11-30) 70 | ------------------- 71 | 72 | * Work on FIPS Python 3.9+, by declaring use of ``hashlib.md5()`` as not used for security. 73 | 74 | Thanks to dantebben for the report in `Issue #414 `__. 75 | 76 | 3.10.2 (2021-11-10) 77 | ------------------- 78 | 79 | * Fix crash when pytest’s cacheprovider is disabled. 80 | 81 | Thanks to Mandeep Sandhu for the report in `Issue #408 82 | `__. 83 | 84 | * Improve group name in ``pytest --help``. 85 | 86 | 3.10.1 (2021-08-13) 87 | ------------------- 88 | 89 | * Fix new shuffling to work when one or more test in a class or module have the 90 | same test id. 91 | 92 | Thanks to Nikita Sobolev for the report in `Issue #378 93 | `__. 94 | 95 | 3.10.0 (2021-08-13) 96 | ------------------- 97 | 98 | * Rework shuffling algorithm to use hashing. This means that running a subset 99 | of tests with the same seed will now produce the same ordering as running the 100 | full set of tests. This allows narrowing down ordering-related failures. 101 | 102 | Thanks to Tom Grainger for the suggestion in `Issue #210 103 | `__. 104 | 105 | * Shuffle before other test collection hooks. This allows 106 | pytest’s `--stepwise flag 107 | `__ to work, among 108 | other things. 109 | 110 | Thanks to Tom Grainger for the suggestion to try with ``--stepwise``. Fixes 111 | `Issue #376 112 | `__. 113 | 114 | 3.9.0 (2021-08-12) 115 | ------------------ 116 | 117 | * Add type hints. 118 | 119 | 3.8.0 (2021-05-10) 120 | ------------------ 121 | 122 | * Support Python 3.10. 123 | 124 | 3.7.0 (2021-04-11) 125 | ------------------ 126 | 127 | * Drop dependency on ``backports.entry-points-selectable`` by depending on 128 | ``importlib-metadata`` version 3.6.0+. 129 | 130 | 3.6.0 (2021-04-01) 131 | ------------------ 132 | 133 | * Fix deprecation warning from importlib-metadata 3.9.0+. 134 | 135 | Thanks to Dominic Davis-Foster for report in `Issue #333 136 | `__. 137 | 138 | * Stop distributing tests to reduce package size. Tests are not intended to be 139 | run outside of the tox setup in the repository. Repackagers can use GitHub's 140 | tarballs per tag. 141 | 142 | * Drop Python 3.5 support. 143 | 144 | 3.5.0 (2020-11-16) 145 | ------------------ 146 | 147 | * Support Python 3.9. 148 | * Move license from BSD to MIT License. 149 | 150 | 3.4.1 (2020-07-10) 151 | ------------------ 152 | 153 | * Fix numpy error ``ValueError: Seed must be between 0 and 2**32 - 1`` when 154 | passed a seed outside of this range. 155 | 156 | 3.4.0 (2020-05-27) 157 | ------------------ 158 | 159 | * Provide a ``faker_seed`` fixture to set the seed for tests using faker's 160 | pytest fixtures (as per its 161 | `docs `__). 162 | 163 | Thanks to Romain Létendart for the change in `PR #261 164 | `__. 165 | 166 | 3.3.1 (2020-04-15) 167 | ------------------ 168 | 169 | * Fix to work when pytest-xdist is not installed or active 170 | (``PluginValidationError: unknown hook 'pytest_configure_node'``). 171 | 172 | 3.3.0 (2020-04-15) 173 | ------------------ 174 | 175 | * Add `pytest-xdist `__ support. 176 | Previously it only worked reliably when setting ``--randomly-seed`` 177 | explicitly. When not provided, the default seed generated in workers could 178 | differ and collection would fail. Now when it is not provided, all xdist 179 | worker processes shared the same default seed generated in the main 180 | process. 181 | 182 | 3.2.1 (2020-01-13) 183 | ------------------ 184 | 185 | * Update ``MANIFEST.in`` so tests are included in the sdist tarball again. 186 | 187 | 3.2.0 (2019-12-19) 188 | ------------------ 189 | 190 | * Converted setuptools metadata to configuration file. This meant removing the 191 | ``__version__`` attribute from the package. If you want to inspect the 192 | installed version, use 193 | ``importlib.metadata.version("pytest-randomly")`` 194 | (`docs `__ / 195 | `backport `__). 196 | * Convert reading entrypoints to use ``importlib.metadata``. Depend on 197 | ``importlib-metadata`` on Python < 3.8. 198 | * Update Python support to 3.5-3.8. 199 | 200 | 3.1.0 (2019-08-25) 201 | ------------------ 202 | 203 | * Add plugins via entry points ``pytest_randomly.random_seeder`` to allow 204 | outside packages to register additional random generators to seed. This has 205 | added a dependency on the ``entrypoints`` package. 206 | 207 | 3.0.0 (2019-04-05) 208 | ------------------ 209 | 210 | * Update Python support to 3.5-3.7, as 3.4 has reached its end of life. 211 | * Handle ``CollectError``\s and ``ImportError``\s during collection when 212 | accessing ``item.module``. 213 | 214 | 2.1.1 (2019-03-26) 215 | ------------------ 216 | 217 | * Fix including tests in sdist after re-arrangement in 2.1.0. 218 | 219 | 2.1.0 (2019-03-01) 220 | ------------------ 221 | 222 | * Add the option ``--randomly-seed=last`` to reuse the last used value for the 223 | seed. 224 | 225 | 2.0.0 (2019-02-28) 226 | ------------------ 227 | 228 | * Drop Python 2 support, only Python 3.4+ is supported now. 229 | 230 | 1.2.3 (2017-12-06) 231 | ------------------ 232 | 233 | * Fix ``DeprecationWarning`` with recent versions of ``factory_boy``. 234 | 235 | 1.2.2 (2017-11-03) 236 | ------------------ 237 | 238 | * Fix collection to not sometimes crash when encountering pytest ``Item``\s 239 | without a module. 240 | 241 | 1.2.1 (2017-06-17) 242 | ------------------ 243 | 244 | * Fix collection to be deterministically shuffled again, regression in 1.2.0. 245 | 246 | 1.2.0 (2017-06-16) 247 | ------------------ 248 | 249 | * Dropped Python 2.6 compatibility, as upstream dependency NumPy did. 250 | * Reset and output the seed at the start of the test run when 251 | ``--randomly-dont-reset-seed`` is set, to allow the reorganization of tests 252 | to be reproducible. 253 | 254 | 1.1.2 (2016-10-27) 255 | ------------------ 256 | 257 | * Reset the random state for NumPy too. 258 | 259 | 1.1.1 (2016-09-16) 260 | ------------------ 261 | 262 | * Add Python 2.6 compatibility 263 | 264 | 1.1.0 (2016-09-12) 265 | ------------------ 266 | 267 | * Offset the random seed during test setup and teardown. This is to avoid the 268 | awkward situation where test setup generates a random object, then the test 269 | generates a second one, but due to the re-seeding, they end up being always 270 | the same object. Thanks @rouge8 for the report. 271 | 272 | 1.0.0 (2016-04-15) 273 | ------------------ 274 | 275 | * First release on PyPI. 276 | -------------------------------------------------------------------------------- /tests/test_pytest_randomly.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import shutil 4 | from unittest import mock 5 | 6 | import pytest 7 | 8 | import pytest_randomly 9 | 10 | pytest_plugins = ["pytester"] 11 | 12 | 13 | @pytest.fixture(autouse=True) 14 | def reset_entrypoints_cache(): 15 | yield 16 | pytest_randomly.entrypoint_reseeds = None 17 | 18 | 19 | @pytest.fixture 20 | def ourtester(pytester): 21 | pytester.makefile( 22 | ".ini", 23 | pytest=""" 24 | [pytest] 25 | console_output_style = classic 26 | """, 27 | ) 28 | 29 | # Change from default running pytest in-process to running in a subprocess 30 | # because numpy imports break with weird: 31 | # File ".../site-packages/numpy/core/overrides.py", line 204, in decorator 32 | # add_docstring(implementation, dispatcher.__doc__) 33 | # RuntimeError: empty_like method already has a docstring 34 | # testdir._runpytest_method = testdir.runpytest_subprocess 35 | 36 | yield pytester 37 | 38 | 39 | @pytest.fixture 40 | def simpletester(ourtester): 41 | ourtester.makepyfile( 42 | test_one=""" 43 | def test_a(): 44 | assert True 45 | """, 46 | ) 47 | yield ourtester 48 | 49 | 50 | def test_it_reports_a_header_when_not_set(simpletester): 51 | out = simpletester.runpytest() 52 | assert len([x for x in out.outlines if x.startswith("Using --randomly-seed=")]) == 1 53 | 54 | 55 | def test_it_reports_a_header_when_set(simpletester): 56 | out = simpletester.runpytest("--randomly-seed=10") 57 | lines = [x for x in out.outlines if x.startswith("Using --randomly-seed=")] 58 | assert lines == ["Using --randomly-seed=10"] 59 | 60 | 61 | def test_it_uses_different_random_seeds_per_test(ourtester): 62 | """ 63 | Run a pair of tests that generate the a number and then assert they got 64 | what the other did. 65 | """ 66 | ourtester.makepyfile( 67 | test_one=""" 68 | import random 69 | 70 | 71 | def test_a(): 72 | global num 73 | num = random.random() 74 | 75 | def test_b(): 76 | assert random.random() != num 77 | """ 78 | ) 79 | out = ourtester.runpytest("--randomly-dont-reorganize", "--randomly-seed=1") 80 | out.assert_outcomes(passed=2, failed=0) 81 | 82 | 83 | def test_without_cacheprovider(ourtester): 84 | ourtester.makepyfile( 85 | test_one=""" 86 | def test_a(): 87 | pass 88 | """ 89 | ) 90 | out = ourtester.runpytest("-p", "no:cacheprovider") 91 | out.assert_outcomes(passed=1, failed=0) 92 | 93 | 94 | def test_using_last_seed(ourtester): 95 | ourtester.makepyfile( 96 | test_one=""" 97 | def test_a(): 98 | pass 99 | """ 100 | ) 101 | out = ourtester.runpytest() 102 | out.assert_outcomes(passed=1, failed=0) 103 | seed_line = [x for x in out.stdout.lines if x.startswith("Using --randomly-seed=")][ 104 | 0 105 | ] 106 | 107 | out = ourtester.runpytest("--randomly-seed=last") 108 | out.assert_outcomes(passed=1, failed=0) 109 | out.stdout.fnmatch_lines([seed_line]) 110 | 111 | 112 | def test_using_last_explicit_seed(ourtester): 113 | ourtester.makepyfile( 114 | test_one=""" 115 | def test_a(): 116 | pass 117 | """ 118 | ) 119 | out = ourtester.runpytest("--randomly-seed=33") 120 | out.assert_outcomes(passed=1, failed=0) 121 | out.stdout.fnmatch_lines(["Using --randomly-seed=33"]) 122 | 123 | out = ourtester.runpytest("--randomly-seed=last") 124 | out.assert_outcomes(passed=1, failed=0) 125 | out.stdout.fnmatch_lines(["Using --randomly-seed=33"]) 126 | 127 | 128 | def test_passing_nonsense_for_randomly_seed(ourtester): 129 | ourtester.makepyfile( 130 | test_one=""" 131 | def test_a(): 132 | pass 133 | """ 134 | ) 135 | out = ourtester.runpytest("--randomly-seed=invalidvalue") 136 | assert out.ret != 0 137 | out.stderr.fnmatch_lines( 138 | [ 139 | ( 140 | "*: error: argument --randomly-seed: 'invalidvalue' " 141 | + "is not an integer or the string 'last'" 142 | ) 143 | ] 144 | ) 145 | 146 | 147 | def test_it_resets_the_random_seed_at_the_start_of_test_classes(ourtester): 148 | ourtester.makepyfile( 149 | test_one=""" 150 | import random 151 | from unittest import TestCase 152 | 153 | 154 | class A(TestCase): 155 | 156 | @classmethod 157 | def setUpClass(cls): 158 | super().setUpClass() 159 | cls.suc_num = random.random() 160 | 161 | def test_fake(self): 162 | assert True 163 | 164 | 165 | class B(TestCase): 166 | 167 | @classmethod 168 | def setUpClass(cls): 169 | super().setUpClass() 170 | cls.suc_num = random.random() 171 | assert cls.suc_num != A.suc_num 172 | 173 | def test_fake(self): 174 | assert True 175 | """ 176 | ) 177 | out = ourtester.runpytest("--randomly-seed=1") 178 | out.assert_outcomes(passed=2, failed=0) 179 | 180 | 181 | def test_it_resets_the_random_seed_at_the_end_of_test_classes(ourtester): 182 | ourtester.makepyfile( 183 | test_one=""" 184 | import random 185 | from unittest import TestCase 186 | 187 | 188 | class A(TestCase): 189 | 190 | def test_fake(self): 191 | assert True 192 | 193 | @classmethod 194 | def tearDownClass(cls): 195 | super().tearDownClass() 196 | cls.suc_num = random.random() 197 | 198 | 199 | class B(TestCase): 200 | 201 | def test_fake(self): 202 | assert True 203 | 204 | @classmethod 205 | def tearDownClass(cls): 206 | super().tearDownClass() 207 | cls.suc_num = random.random() 208 | assert cls.suc_num != A.suc_num 209 | """ 210 | ) 211 | out = ourtester.runpytest("--randomly-seed=1") 212 | out.assert_outcomes(passed=2, failed=0) 213 | 214 | 215 | def test_the_same_random_seed_per_test_can_be_turned_off(ourtester): 216 | ourtester.makepyfile( 217 | test_one=""" 218 | import random 219 | 220 | def test_a(): 221 | test_a.state1 = random.getstate() 222 | assert test_a.state1 == random.getstate() # sanity check 223 | assert random.random() >= 0 # mutate state 224 | test_a.state2 = random.getstate() 225 | 226 | def test_b(): 227 | test_b.state = random.getstate() 228 | assert test_b.state == random.getstate() # sanity check 229 | assert test_a.state1 != test_b.state 230 | assert test_a.state2 == test_b.state 231 | """ 232 | ) 233 | out = ourtester.runpytest( 234 | "--randomly-dont-reset-seed", "--randomly-dont-reorganize" 235 | ) 236 | out.assert_outcomes(passed=2, failed=0) 237 | 238 | 239 | def test_files_reordered(ourtester): 240 | code = """ 241 | def test_it(): 242 | pass 243 | """ 244 | ourtester.makepyfile(test_a=code, test_b=code, test_c=code, test_d=code) 245 | args = ["-v", "--randomly-seed=15"] 246 | 247 | out = ourtester.runpytest(*args) 248 | 249 | out.assert_outcomes(passed=4, failed=0) 250 | assert out.outlines[9:13] == [ 251 | "test_c.py::test_it PASSED", 252 | "test_b.py::test_it PASSED", 253 | "test_d.py::test_it PASSED", 254 | "test_a.py::test_it PASSED", 255 | ] 256 | 257 | 258 | def test_files_reordered_when_seed_not_reset(ourtester): 259 | code = """ 260 | def test_it(): 261 | pass 262 | """ 263 | ourtester.makepyfile(test_a=code, test_b=code, test_c=code, test_d=code) 264 | args = ["-v", "--randomly-seed=15"] 265 | 266 | args.append("--randomly-dont-reset-seed") 267 | out = ourtester.runpytest(*args) 268 | 269 | out.assert_outcomes(passed=4, failed=0) 270 | assert out.outlines[9:13] == [ 271 | "test_c.py::test_it PASSED", 272 | "test_b.py::test_it PASSED", 273 | "test_d.py::test_it PASSED", 274 | "test_a.py::test_it PASSED", 275 | ] 276 | 277 | 278 | def test_classes_reordered(ourtester): 279 | ourtester.makepyfile( 280 | test_one=""" 281 | from unittest import TestCase 282 | 283 | 284 | class A(TestCase): 285 | def test_a(self): 286 | pass 287 | 288 | 289 | class B(TestCase): 290 | def test_b(self): 291 | pass 292 | 293 | 294 | class C(TestCase): 295 | def test_c(self): 296 | pass 297 | 298 | 299 | class D(TestCase): 300 | def test_d(self): 301 | pass 302 | """ 303 | ) 304 | args = ["-v", "--randomly-seed=15"] 305 | 306 | out = ourtester.runpytest(*args) 307 | 308 | out.assert_outcomes(passed=4, failed=0) 309 | assert out.outlines[9:13] == [ 310 | "test_one.py::D::test_d PASSED", 311 | "test_one.py::A::test_a PASSED", 312 | "test_one.py::C::test_c PASSED", 313 | "test_one.py::B::test_b PASSED", 314 | ] 315 | 316 | 317 | def test_class_test_methods_reordered(ourtester): 318 | ourtester.makepyfile( 319 | test_one=""" 320 | from unittest import TestCase 321 | 322 | class T(TestCase): 323 | def test_a(self): 324 | pass 325 | 326 | def test_b(self): 327 | pass 328 | 329 | def test_c(self): 330 | pass 331 | 332 | def test_d(self): 333 | pass 334 | """ 335 | ) 336 | args = ["-v", "--randomly-seed=15"] 337 | 338 | out = ourtester.runpytest(*args) 339 | 340 | out.assert_outcomes(passed=4, failed=0) 341 | assert out.outlines[9:13] == [ 342 | "test_one.py::T::test_c PASSED", 343 | "test_one.py::T::test_b PASSED", 344 | "test_one.py::T::test_d PASSED", 345 | "test_one.py::T::test_a PASSED", 346 | ] 347 | 348 | 349 | def test_test_functions_reordered(ourtester): 350 | ourtester.makepyfile( 351 | test_one=""" 352 | def test_a(): 353 | pass 354 | 355 | def test_b(): 356 | pass 357 | 358 | def test_c(): 359 | pass 360 | 361 | def test_d(): 362 | pass 363 | """ 364 | ) 365 | args = ["-v", "--randomly-seed=15"] 366 | 367 | out = ourtester.runpytest(*args) 368 | 369 | out.assert_outcomes(passed=4, failed=0) 370 | assert out.outlines[9:13] == [ 371 | "test_one.py::test_d PASSED", 372 | "test_one.py::test_a PASSED", 373 | "test_one.py::test_c PASSED", 374 | "test_one.py::test_b PASSED", 375 | ] 376 | 377 | 378 | def test_test_functions_reordered_when_randomness_in_module(ourtester): 379 | ourtester.makepyfile( 380 | test_one=""" 381 | import random 382 | import time 383 | 384 | random.seed(time.time() * 100) 385 | 386 | def test_a(): 387 | pass 388 | 389 | def test_b(): 390 | pass 391 | 392 | def test_c(): 393 | pass 394 | 395 | def test_d(): 396 | pass 397 | """ 398 | ) 399 | args = ["-v", "--randomly-seed=15"] 400 | 401 | out = ourtester.runpytest(*args) 402 | 403 | out.assert_outcomes(passed=4, failed=0) 404 | assert out.outlines[9:13] == [ 405 | "test_one.py::test_d PASSED", 406 | "test_one.py::test_a PASSED", 407 | "test_one.py::test_c PASSED", 408 | "test_one.py::test_b PASSED", 409 | ] 410 | 411 | 412 | def test_doctests_reordered(ourtester): 413 | ourtester.makepyfile( 414 | test_one=""" 415 | def foo(): 416 | ''' 417 | >>> foo() 418 | 9001 419 | ''' 420 | return 9001 421 | 422 | def bar(): 423 | ''' 424 | >>> bar() 425 | 9002 426 | ''' 427 | return 9002 428 | """ 429 | ) 430 | args = ["-v", "--doctest-modules", "--randomly-seed=1"] 431 | 432 | out = ourtester.runpytest(*args) 433 | out.assert_outcomes(passed=2) 434 | assert out.outlines[9:11] == [ 435 | "test_one.py::test_one.bar PASSED", 436 | "test_one.py::test_one.foo PASSED", 437 | ] 438 | 439 | 440 | def test_it_works_with_the_simplest_test_items(ourtester): 441 | ourtester.makepyfile( 442 | conftest=""" 443 | import sys 444 | 445 | import pytest 446 | 447 | 448 | class MyCollector(pytest.Collector): 449 | def __init__(self, fspath, items, **kwargs): 450 | super(MyCollector, self).__init__(fspath, **kwargs) 451 | self.items = items 452 | 453 | def collect(self): 454 | return self.items 455 | 456 | 457 | class NoOpItem(pytest.Item): 458 | def __init__(self, name, parent, module=None): 459 | super(NoOpItem, self).__init__(name=name, parent=parent) 460 | if module is not None: 461 | self.module = module 462 | 463 | def runtest(self): 464 | pass 465 | 466 | 467 | def pytest_collect_file(file_path, parent): 468 | if not str(file_path).endswith('.py'): 469 | return 470 | return MyCollector.from_parent( 471 | parent=parent, 472 | fspath=str(file_path), 473 | items=[ 474 | NoOpItem.from_parent( 475 | name=str(file_path) + "1", 476 | parent=parent, 477 | module=sys.modules[__name__], 478 | ), 479 | NoOpItem.from_parent( 480 | name=str(file_path) + "1", 481 | parent=parent, 482 | module=sys.modules[__name__], 483 | ), 484 | NoOpItem.from_parent( 485 | name=str(file_path) + "2", 486 | parent=parent, 487 | ), 488 | ], 489 | ) 490 | """ 491 | ) 492 | args = ["-v"] 493 | 494 | out = ourtester.runpytest(*args) 495 | out.assert_outcomes(passed=3) 496 | 497 | 498 | def test_doctests_in_txt_files_reordered(ourtester): 499 | ourtester.makefile( 500 | ".txt", 501 | test=""" 502 | >>> 2 + 2 503 | 4 504 | """, 505 | test2=""" 506 | >>> 2 - 2 507 | 0 508 | """, 509 | ) 510 | args = ["-v", "--randomly-seed=2"] 511 | 512 | out = ourtester.runpytest(*args) 513 | out.assert_outcomes(passed=2) 514 | assert out.outlines[9:11] == [ 515 | "test2.txt::test2.txt PASSED", 516 | "test.txt::test.txt PASSED", 517 | ] 518 | 519 | 520 | def test_it_runs_before_stepwise(ourtester): 521 | ourtester.makepyfile( 522 | test_one=""" 523 | def test_a(): 524 | assert 0 525 | 526 | 527 | def test_b(): 528 | assert 0 529 | """ 530 | ) 531 | out = ourtester.runpytest("-v", "--randomly-seed=8") 532 | out.assert_outcomes(failed=2) 533 | # Ensure test_b runs first 534 | assert out.outlines[9:11] == [ 535 | "test_one.py::test_b FAILED", 536 | "test_one.py::test_a FAILED", 537 | ] 538 | 539 | out = ourtester.runpytest("--randomly-seed=8", "--stepwise") 540 | out.assert_outcomes(failed=1) 541 | 542 | # Now make test_b pass 543 | ourtester.makepyfile( 544 | test_one=""" 545 | def test_a(): 546 | assert 0 547 | 548 | 549 | def test_b(): 550 | assert 1 551 | """ 552 | ) 553 | shutil.rmtree(ourtester.path / "__pycache__") 554 | out = ourtester.runpytest("--randomly-seed=8", "--stepwise") 555 | out.assert_outcomes(passed=1, failed=1) 556 | out = ourtester.runpytest("--randomly-seed=8", "--stepwise") 557 | out.assert_outcomes(failed=1) 558 | 559 | 560 | def test_fixtures_get_different_random_state_to_tests(ourtester): 561 | ourtester.makepyfile( 562 | test_one=""" 563 | import random 564 | 565 | import pytest 566 | 567 | 568 | @pytest.fixture() 569 | def myfixture(): 570 | return random.getstate() 571 | 572 | 573 | def test_one(myfixture): 574 | assert myfixture != random.getstate() 575 | """ 576 | ) 577 | out = ourtester.runpytest() 578 | out.assert_outcomes(passed=1) 579 | 580 | 581 | def test_factory_boy(ourtester): 582 | """ 583 | Check that the random generator factory boy uses is different between two tests. 584 | """ 585 | ourtester.makepyfile( 586 | test_one=""" 587 | from factory.random import randgen 588 | 589 | def test_a(): 590 | assert randgen.random() == 0.17867277194477893 591 | 592 | 593 | def test_b(): 594 | assert randgen.random() == 0.8026272812225962 595 | """ 596 | ) 597 | 598 | out = ourtester.runpytest("--randomly-seed=1") 599 | out.assert_outcomes(passed=2) 600 | 601 | 602 | def test_faker(ourtester): 603 | ourtester.makepyfile( 604 | test_one=""" 605 | from faker import Faker 606 | 607 | fake = Faker() 608 | 609 | def test_one(): 610 | assert fake.name() == 'Kimberly Powell' 611 | 612 | def test_two(): 613 | assert fake.name() == 'Thomas Moyer PhD' 614 | """ 615 | ) 616 | 617 | out = ourtester.runpytest("--randomly-seed=1") 618 | out.assert_outcomes(passed=2) 619 | 620 | 621 | def test_faker_fixture(ourtester): 622 | ourtester.makepyfile( 623 | test_one=""" 624 | def test_one(faker): 625 | assert faker.name() == 'Kimberly Powell' 626 | 627 | def test_two(faker): 628 | assert faker.name() == 'Thomas Moyer PhD' 629 | """ 630 | ) 631 | 632 | out = ourtester.runpytest("--randomly-seed=1") 633 | out.assert_outcomes(passed=2) 634 | 635 | 636 | def test_model_bakery(ourtester): 637 | """ 638 | Check the Model Bakery random generator is reset between tests. 639 | """ 640 | ourtester.makepyfile( 641 | test_one=""" 642 | from model_bakery.random_gen import gen_slug 643 | 644 | def test_a(): 645 | assert gen_slug(10) == 'whwhAKeQYE' 646 | 647 | def test_b(): 648 | assert gen_slug(10) == 'o2N4p5UAXd' 649 | """ 650 | ) 651 | 652 | out = ourtester.runpytest("--randomly-seed=1") 653 | out.assert_outcomes(passed=2) 654 | 655 | 656 | def test_numpy(ourtester): 657 | ourtester.makepyfile( 658 | test_one=""" 659 | import numpy as np 660 | 661 | def test_one(): 662 | assert np.random.rand() == 0.1610140063074521 663 | 664 | def test_two(): 665 | assert np.random.rand() == 0.6896867238957805 666 | """ 667 | ) 668 | 669 | out = ourtester.runpytest("--randomly-seed=1") 670 | out.assert_outcomes(passed=2) 671 | 672 | 673 | def test_numpy_doesnt_crash_with_large_seed(ourtester): 674 | ourtester.makepyfile( 675 | test_one=""" 676 | import numpy as np 677 | 678 | def test_one(): 679 | assert np.random.rand() >= 0.0 680 | """ 681 | ) 682 | 683 | out = ourtester.runpytest("--randomly-seed=7106521602475165645") 684 | out.assert_outcomes(passed=1) 685 | 686 | 687 | def test_failing_import(testdir): 688 | """Test with pytest raising CollectError or ImportError. 689 | 690 | This happens when trying to access item.module during 691 | pytest_collection_modifyitems. 692 | """ 693 | modcol = testdir.getmodulecol("import alksdjalskdjalkjals") 694 | assert modcol.instance is None 695 | 696 | modcol = testdir.getmodulecol("pytest_plugins='xasdlkj',") 697 | with pytest.raises(ImportError): 698 | modcol.obj # noqa: B018 699 | 700 | 701 | def test_entrypoint_injection(pytester, monkeypatch): 702 | """Test that registered entry points are seeded""" 703 | (pytester.path / "test_one.py").write_text("def test_one(): pass\n") 704 | 705 | class _FakeEntryPoint: 706 | """Minimal surface of Entry point API to allow testing""" 707 | 708 | def __init__(self, name: str, obj: mock.Mock) -> None: 709 | self.name = name 710 | self._obj = obj 711 | 712 | def load(self) -> mock.Mock: 713 | return self._obj 714 | 715 | entry_points: list[_FakeEntryPoint] = [] 716 | 717 | def fake_entry_points(*, group): 718 | return entry_points 719 | 720 | monkeypatch.setattr(pytest_randomly, "entry_points", fake_entry_points) 721 | reseed = mock.Mock() 722 | entry_points.append(_FakeEntryPoint("test_seeder", reseed)) 723 | 724 | # Need to run in-process so that monkeypatching works 725 | pytester.runpytest_inprocess("--randomly-seed=1") 726 | assert reseed.mock_calls == [ 727 | mock.call(1), 728 | mock.call(1), 729 | mock.call(2964001072), 730 | mock.call(2964001073), 731 | mock.call(2964001074), 732 | ] 733 | 734 | reseed.mock_calls[:] = [] 735 | pytester.runpytest_inprocess("--randomly-seed=424242") 736 | assert reseed.mock_calls == [ 737 | mock.call(424242), 738 | mock.call(424242), 739 | mock.call(2964425313), 740 | mock.call(2964425314), 741 | mock.call(2964425315), 742 | ] 743 | 744 | 745 | def test_entrypoint_missing(pytester, monkeypatch): 746 | """ 747 | Test that if there aren't any registered entrypoints, it doesn't crash 748 | """ 749 | (pytester.path / "test_one.py").write_text("def test_one(): pass\n") 750 | 751 | def fake_entry_points(group): 752 | return [] 753 | 754 | monkeypatch.setattr(pytest_randomly, "entry_points", fake_entry_points) 755 | 756 | # Need to run in-process so that monkeypatching works 757 | result = pytester.runpytest_inprocess("--randomly-seed=1") 758 | 759 | assert result.ret == 0 760 | 761 | 762 | def test_works_without_xdist(simpletester): 763 | out = simpletester.runpytest("-p", "no:xdist") 764 | out.assert_outcomes(passed=1) 765 | 766 | 767 | @pytest.mark.parametrize("n", list(range(5))) 768 | def test_xdist(n, ourtester): 769 | """ 770 | This test does not expose the original bug (non-shared default seeds) with 771 | a very high probability, hence multiple runs. 772 | """ 773 | ourtester.makepyfile( 774 | test_one="def test_a(): pass", 775 | test_two="def test_a(): pass", 776 | test_three="def test_a(): pass", 777 | test_four="def test_a(): pass", 778 | test_five="def test_a(): pass", 779 | test_six="def test_a(): pass", 780 | ) 781 | 782 | out = ourtester.runpytest("-n", "6", "-v", "--dist=loadfile") 783 | out.assert_outcomes(passed=6) 784 | 785 | # Can't make any assertion on the order, since output comes back from 786 | # workers non-deterministically 787 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 3 3 | requires-python = ">=3.10" 4 | resolution-markers = [ 5 | "python_full_version >= '3.12'", 6 | "python_full_version == '3.11.*'", 7 | "python_full_version < '3.11'", 8 | ] 9 | 10 | [[package]] 11 | name = "asgiref" 12 | version = "3.11.0" 13 | source = { registry = "https://pypi.org/simple" } 14 | dependencies = [ 15 | { name = "typing-extensions", marker = "python_full_version < '3.11'" }, 16 | ] 17 | sdist = { url = "https://files.pythonhosted.org/packages/76/b9/4db2509eabd14b4a8c71d1b24c8d5734c52b8560a7b1e1a8b56c8d25568b/asgiref-3.11.0.tar.gz", hash = "sha256:13acff32519542a1736223fb79a715acdebe24286d98e8b164a73085f40da2c4", size = 37969, upload-time = "2025-11-19T15:32:20.106Z" } 18 | wheels = [ 19 | { url = "https://files.pythonhosted.org/packages/91/be/317c2c55b8bbec407257d45f5c8d1b6867abc76d12043f2d3d58c538a4ea/asgiref-3.11.0-py3-none-any.whl", hash = "sha256:1db9021efadb0d9512ce8ffaf72fcef601c7b73a8807a1bb2ef143dc6b14846d", size = 24096, upload-time = "2025-11-19T15:32:19.004Z" }, 20 | ] 21 | 22 | [[package]] 23 | name = "colorama" 24 | version = "0.4.6" 25 | source = { registry = "https://pypi.org/simple" } 26 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } 27 | wheels = [ 28 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, 29 | ] 30 | 31 | [[package]] 32 | name = "coverage" 33 | version = "7.12.0" 34 | source = { registry = "https://pypi.org/simple" } 35 | sdist = { url = "https://files.pythonhosted.org/packages/89/26/4a96807b193b011588099c3b5c89fbb05294e5b90e71018e065465f34eb6/coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c", size = 819341, upload-time = "2025-11-18T13:34:20.766Z" } 36 | wheels = [ 37 | { url = "https://files.pythonhosted.org/packages/26/4a/0dc3de1c172d35abe512332cfdcc43211b6ebce629e4cc42e6cd25ed8f4d/coverage-7.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:32b75c2ba3f324ee37af3ccee5b30458038c50b349ad9b88cee85096132a575b", size = 217409, upload-time = "2025-11-18T13:31:53.122Z" }, 38 | { url = "https://files.pythonhosted.org/packages/01/c3/086198b98db0109ad4f84241e8e9ea7e5fb2db8c8ffb787162d40c26cc76/coverage-7.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cb2a1b6ab9fe833714a483a915de350abc624a37149649297624c8d57add089c", size = 217927, upload-time = "2025-11-18T13:31:54.458Z" }, 39 | { url = "https://files.pythonhosted.org/packages/5d/5f/34614dbf5ce0420828fc6c6f915126a0fcb01e25d16cf141bf5361e6aea6/coverage-7.12.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5734b5d913c3755e72f70bf6cc37a0518d4f4745cde760c5d8e12005e62f9832", size = 244678, upload-time = "2025-11-18T13:31:55.805Z" }, 40 | { url = "https://files.pythonhosted.org/packages/55/7b/6b26fb32e8e4a6989ac1d40c4e132b14556131493b1d06bc0f2be169c357/coverage-7.12.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b527a08cdf15753279b7afb2339a12073620b761d79b81cbe2cdebdb43d90daa", size = 246507, upload-time = "2025-11-18T13:31:57.05Z" }, 41 | { url = "https://files.pythonhosted.org/packages/06/42/7d70e6603d3260199b90fb48b537ca29ac183d524a65cc31366b2e905fad/coverage-7.12.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bb44c889fb68004e94cab71f6a021ec83eac9aeabdbb5a5a88821ec46e1da73", size = 248366, upload-time = "2025-11-18T13:31:58.362Z" }, 42 | { url = "https://files.pythonhosted.org/packages/2d/4a/d86b837923878424c72458c5b25e899a3c5ca73e663082a915f5b3c4d749/coverage-7.12.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b59b501455535e2e5dde5881739897967b272ba25988c89145c12d772810ccb", size = 245366, upload-time = "2025-11-18T13:31:59.572Z" }, 43 | { url = "https://files.pythonhosted.org/packages/e6/c2/2adec557e0aa9721875f06ced19730fdb7fc58e31b02b5aa56f2ebe4944d/coverage-7.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8842f17095b9868a05837b7b1b73495293091bed870e099521ada176aa3e00e", size = 246408, upload-time = "2025-11-18T13:32:00.784Z" }, 44 | { url = "https://files.pythonhosted.org/packages/5a/4b/8bd1f1148260df11c618e535fdccd1e5aaf646e55b50759006a4f41d8a26/coverage-7.12.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5a6f20bf48b8866095c6820641e7ffbe23f2ac84a2efc218d91235e404c7777", size = 244416, upload-time = "2025-11-18T13:32:01.963Z" }, 45 | { url = "https://files.pythonhosted.org/packages/0e/13/3a248dd6a83df90414c54a4e121fd081fb20602ca43955fbe1d60e2312a9/coverage-7.12.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5f3738279524e988d9da2893f307c2093815c623f8d05a8f79e3eff3a7a9e553", size = 244681, upload-time = "2025-11-18T13:32:03.408Z" }, 46 | { url = "https://files.pythonhosted.org/packages/76/30/aa833827465a5e8c938935f5d91ba055f70516941078a703740aaf1aa41f/coverage-7.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0d68c1f7eabbc8abe582d11fa393ea483caf4f44b0af86881174769f185c94d", size = 245300, upload-time = "2025-11-18T13:32:04.686Z" }, 47 | { url = "https://files.pythonhosted.org/packages/38/24/f85b3843af1370fb3739fa7571819b71243daa311289b31214fe3e8c9d68/coverage-7.12.0-cp310-cp310-win32.whl", hash = "sha256:7670d860e18b1e3ee5930b17a7d55ae6287ec6e55d9799982aa103a2cc1fa2ef", size = 220008, upload-time = "2025-11-18T13:32:05.806Z" }, 48 | { url = "https://files.pythonhosted.org/packages/3a/a2/c7da5b9566f7164db9eefa133d17761ecb2c2fde9385d754e5b5c80f710d/coverage-7.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:f999813dddeb2a56aab5841e687b68169da0d3f6fc78ccf50952fa2463746022", size = 220943, upload-time = "2025-11-18T13:32:07.166Z" }, 49 | { url = "https://files.pythonhosted.org/packages/5a/0c/0dfe7f0487477d96432e4815537263363fb6dd7289743a796e8e51eabdf2/coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f", size = 217535, upload-time = "2025-11-18T13:32:08.812Z" }, 50 | { url = "https://files.pythonhosted.org/packages/9b/f5/f9a4a053a5bbff023d3bec259faac8f11a1e5a6479c2ccf586f910d8dac7/coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3", size = 218044, upload-time = "2025-11-18T13:32:10.329Z" }, 51 | { url = "https://files.pythonhosted.org/packages/95/c5/84fc3697c1fa10cd8571919bf9693f693b7373278daaf3b73e328d502bc8/coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e", size = 248440, upload-time = "2025-11-18T13:32:12.536Z" }, 52 | { url = "https://files.pythonhosted.org/packages/f4/36/2d93fbf6a04670f3874aed397d5a5371948a076e3249244a9e84fb0e02d6/coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7", size = 250361, upload-time = "2025-11-18T13:32:13.852Z" }, 53 | { url = "https://files.pythonhosted.org/packages/5d/49/66dc65cc456a6bfc41ea3d0758c4afeaa4068a2b2931bf83be6894cf1058/coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245", size = 252472, upload-time = "2025-11-18T13:32:15.068Z" }, 54 | { url = "https://files.pythonhosted.org/packages/35/1f/ebb8a18dffd406db9fcd4b3ae42254aedcaf612470e8712f12041325930f/coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b", size = 248592, upload-time = "2025-11-18T13:32:16.328Z" }, 55 | { url = "https://files.pythonhosted.org/packages/da/a8/67f213c06e5ea3b3d4980df7dc344d7fea88240b5fe878a5dcbdfe0e2315/coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64", size = 250167, upload-time = "2025-11-18T13:32:17.687Z" }, 56 | { url = "https://files.pythonhosted.org/packages/f0/00/e52aef68154164ea40cc8389c120c314c747fe63a04b013a5782e989b77f/coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742", size = 248238, upload-time = "2025-11-18T13:32:19.2Z" }, 57 | { url = "https://files.pythonhosted.org/packages/1f/a4/4d88750bcf9d6d66f77865e5a05a20e14db44074c25fd22519777cb69025/coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c", size = 247964, upload-time = "2025-11-18T13:32:21.027Z" }, 58 | { url = "https://files.pythonhosted.org/packages/a7/6b/b74693158899d5b47b0bf6238d2c6722e20ba749f86b74454fac0696bb00/coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984", size = 248862, upload-time = "2025-11-18T13:32:22.304Z" }, 59 | { url = "https://files.pythonhosted.org/packages/18/de/6af6730227ce0e8ade307b1cc4a08e7f51b419a78d02083a86c04ccceb29/coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6", size = 220033, upload-time = "2025-11-18T13:32:23.714Z" }, 60 | { url = "https://files.pythonhosted.org/packages/e2/a1/e7f63021a7c4fe20994359fcdeae43cbef4a4d0ca36a5a1639feeea5d9e1/coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4", size = 220966, upload-time = "2025-11-18T13:32:25.599Z" }, 61 | { url = "https://files.pythonhosted.org/packages/77/e8/deae26453f37c20c3aa0c4433a1e32cdc169bf415cce223a693117aa3ddd/coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc", size = 219637, upload-time = "2025-11-18T13:32:27.265Z" }, 62 | { url = "https://files.pythonhosted.org/packages/02/bf/638c0427c0f0d47638242e2438127f3c8ee3cfc06c7fdeb16778ed47f836/coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647", size = 217704, upload-time = "2025-11-18T13:32:28.906Z" }, 63 | { url = "https://files.pythonhosted.org/packages/08/e1/706fae6692a66c2d6b871a608bbde0da6281903fa0e9f53a39ed441da36a/coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736", size = 218064, upload-time = "2025-11-18T13:32:30.161Z" }, 64 | { url = "https://files.pythonhosted.org/packages/a9/8b/eb0231d0540f8af3ffda39720ff43cb91926489d01524e68f60e961366e4/coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60", size = 249560, upload-time = "2025-11-18T13:32:31.835Z" }, 65 | { url = "https://files.pythonhosted.org/packages/e9/a1/67fb52af642e974d159b5b379e4d4c59d0ebe1288677fbd04bbffe665a82/coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8", size = 252318, upload-time = "2025-11-18T13:32:33.178Z" }, 66 | { url = "https://files.pythonhosted.org/packages/41/e5/38228f31b2c7665ebf9bdfdddd7a184d56450755c7e43ac721c11a4b8dab/coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f", size = 253403, upload-time = "2025-11-18T13:32:34.45Z" }, 67 | { url = "https://files.pythonhosted.org/packages/ec/4b/df78e4c8188f9960684267c5a4897836f3f0f20a20c51606ee778a1d9749/coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70", size = 249984, upload-time = "2025-11-18T13:32:35.747Z" }, 68 | { url = "https://files.pythonhosted.org/packages/ba/51/bb163933d195a345c6f63eab9e55743413d064c291b6220df754075c2769/coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0", size = 251339, upload-time = "2025-11-18T13:32:37.352Z" }, 69 | { url = "https://files.pythonhosted.org/packages/15/40/c9b29cdb8412c837cdcbc2cfa054547dd83affe6cbbd4ce4fdb92b6ba7d1/coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068", size = 249489, upload-time = "2025-11-18T13:32:39.212Z" }, 70 | { url = "https://files.pythonhosted.org/packages/c8/da/b3131e20ba07a0de4437a50ef3b47840dfabf9293675b0cd5c2c7f66dd61/coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b", size = 249070, upload-time = "2025-11-18T13:32:40.598Z" }, 71 | { url = "https://files.pythonhosted.org/packages/70/81/b653329b5f6302c08d683ceff6785bc60a34be9ae92a5c7b63ee7ee7acec/coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937", size = 250929, upload-time = "2025-11-18T13:32:42.915Z" }, 72 | { url = "https://files.pythonhosted.org/packages/a3/00/250ac3bca9f252a5fb1338b5ad01331ebb7b40223f72bef5b1b2cb03aa64/coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa", size = 220241, upload-time = "2025-11-18T13:32:44.665Z" }, 73 | { url = "https://files.pythonhosted.org/packages/64/1c/77e79e76d37ce83302f6c21980b45e09f8aa4551965213a10e62d71ce0ab/coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a", size = 221051, upload-time = "2025-11-18T13:32:46.008Z" }, 74 | { url = "https://files.pythonhosted.org/packages/31/f5/641b8a25baae564f9e52cac0e2667b123de961985709a004e287ee7663cc/coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c", size = 219692, upload-time = "2025-11-18T13:32:47.372Z" }, 75 | { url = "https://files.pythonhosted.org/packages/b8/14/771700b4048774e48d2c54ed0c674273702713c9ee7acdfede40c2666747/coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941", size = 217725, upload-time = "2025-11-18T13:32:49.22Z" }, 76 | { url = "https://files.pythonhosted.org/packages/17/a7/3aa4144d3bcb719bf67b22d2d51c2d577bf801498c13cb08f64173e80497/coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a", size = 218098, upload-time = "2025-11-18T13:32:50.78Z" }, 77 | { url = "https://files.pythonhosted.org/packages/fc/9c/b846bbc774ff81091a12a10203e70562c91ae71badda00c5ae5b613527b1/coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d", size = 249093, upload-time = "2025-11-18T13:32:52.554Z" }, 78 | { url = "https://files.pythonhosted.org/packages/76/b6/67d7c0e1f400b32c883e9342de4a8c2ae7c1a0b57c5de87622b7262e2309/coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211", size = 251686, upload-time = "2025-11-18T13:32:54.862Z" }, 79 | { url = "https://files.pythonhosted.org/packages/cc/75/b095bd4b39d49c3be4bffbb3135fea18a99a431c52dd7513637c0762fecb/coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d", size = 252930, upload-time = "2025-11-18T13:32:56.417Z" }, 80 | { url = "https://files.pythonhosted.org/packages/6e/f3/466f63015c7c80550bead3093aacabf5380c1220a2a93c35d374cae8f762/coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c", size = 249296, upload-time = "2025-11-18T13:32:58.074Z" }, 81 | { url = "https://files.pythonhosted.org/packages/27/86/eba2209bf2b7e28c68698fc13437519a295b2d228ba9e0ec91673e09fa92/coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9", size = 251068, upload-time = "2025-11-18T13:32:59.646Z" }, 82 | { url = "https://files.pythonhosted.org/packages/ec/55/ca8ae7dbba962a3351f18940b359b94c6bafdd7757945fdc79ec9e452dc7/coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0", size = 249034, upload-time = "2025-11-18T13:33:01.481Z" }, 83 | { url = "https://files.pythonhosted.org/packages/7a/d7/39136149325cad92d420b023b5fd900dabdd1c3a0d1d5f148ef4a8cedef5/coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508", size = 248853, upload-time = "2025-11-18T13:33:02.935Z" }, 84 | { url = "https://files.pythonhosted.org/packages/fe/b6/76e1add8b87ef60e00643b0b7f8f7bb73d4bf5249a3be19ebefc5793dd25/coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc", size = 250619, upload-time = "2025-11-18T13:33:04.336Z" }, 85 | { url = "https://files.pythonhosted.org/packages/95/87/924c6dc64f9203f7a3c1832a6a0eee5a8335dbe5f1bdadcc278d6f1b4d74/coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8", size = 220261, upload-time = "2025-11-18T13:33:06.493Z" }, 86 | { url = "https://files.pythonhosted.org/packages/91/77/dd4aff9af16ff776bf355a24d87eeb48fc6acde54c907cc1ea89b14a8804/coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07", size = 221072, upload-time = "2025-11-18T13:33:07.926Z" }, 87 | { url = "https://files.pythonhosted.org/packages/70/49/5c9dc46205fef31b1b226a6e16513193715290584317fd4df91cdaf28b22/coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc", size = 219702, upload-time = "2025-11-18T13:33:09.631Z" }, 88 | { url = "https://files.pythonhosted.org/packages/9b/62/f87922641c7198667994dd472a91e1d9b829c95d6c29529ceb52132436ad/coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87", size = 218420, upload-time = "2025-11-18T13:33:11.153Z" }, 89 | { url = "https://files.pythonhosted.org/packages/85/dd/1cc13b2395ef15dbb27d7370a2509b4aee77890a464fb35d72d428f84871/coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6", size = 218773, upload-time = "2025-11-18T13:33:12.569Z" }, 90 | { url = "https://files.pythonhosted.org/packages/74/40/35773cc4bb1e9d4658d4fb669eb4195b3151bef3bbd6f866aba5cd5dac82/coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7", size = 260078, upload-time = "2025-11-18T13:33:14.037Z" }, 91 | { url = "https://files.pythonhosted.org/packages/ec/ee/231bb1a6ffc2905e396557585ebc6bdc559e7c66708376d245a1f1d330fc/coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560", size = 262144, upload-time = "2025-11-18T13:33:15.601Z" }, 92 | { url = "https://files.pythonhosted.org/packages/28/be/32f4aa9f3bf0b56f3971001b56508352c7753915345d45fab4296a986f01/coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12", size = 264574, upload-time = "2025-11-18T13:33:17.354Z" }, 93 | { url = "https://files.pythonhosted.org/packages/68/7c/00489fcbc2245d13ab12189b977e0cf06ff3351cb98bc6beba8bd68c5902/coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296", size = 259298, upload-time = "2025-11-18T13:33:18.958Z" }, 94 | { url = "https://files.pythonhosted.org/packages/96/b4/f0760d65d56c3bea95b449e02570d4abd2549dc784bf39a2d4721a2d8ceb/coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507", size = 262150, upload-time = "2025-11-18T13:33:20.644Z" }, 95 | { url = "https://files.pythonhosted.org/packages/c5/71/9a9314df00f9326d78c1e5a910f520d599205907432d90d1c1b7a97aa4b1/coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d", size = 259763, upload-time = "2025-11-18T13:33:22.189Z" }, 96 | { url = "https://files.pythonhosted.org/packages/10/34/01a0aceed13fbdf925876b9a15d50862eb8845454301fe3cdd1df08b2182/coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2", size = 258653, upload-time = "2025-11-18T13:33:24.239Z" }, 97 | { url = "https://files.pythonhosted.org/packages/8d/04/81d8fd64928acf1574bbb0181f66901c6c1c6279c8ccf5f84259d2c68ae9/coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455", size = 260856, upload-time = "2025-11-18T13:33:26.365Z" }, 98 | { url = "https://files.pythonhosted.org/packages/f2/76/fa2a37bfaeaf1f766a2d2360a25a5297d4fb567098112f6517475eee120b/coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d", size = 220936, upload-time = "2025-11-18T13:33:28.165Z" }, 99 | { url = "https://files.pythonhosted.org/packages/f9/52/60f64d932d555102611c366afb0eb434b34266b1d9266fc2fe18ab641c47/coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c", size = 222001, upload-time = "2025-11-18T13:33:29.656Z" }, 100 | { url = "https://files.pythonhosted.org/packages/77/df/c303164154a5a3aea7472bf323b7c857fed93b26618ed9fc5c2955566bb0/coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d", size = 220273, upload-time = "2025-11-18T13:33:31.415Z" }, 101 | { url = "https://files.pythonhosted.org/packages/bf/2e/fc12db0883478d6e12bbd62d481210f0c8daf036102aa11434a0c5755825/coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92", size = 217777, upload-time = "2025-11-18T13:33:32.86Z" }, 102 | { url = "https://files.pythonhosted.org/packages/1f/c1/ce3e525d223350c6ec16b9be8a057623f54226ef7f4c2fee361ebb6a02b8/coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360", size = 218100, upload-time = "2025-11-18T13:33:34.532Z" }, 103 | { url = "https://files.pythonhosted.org/packages/15/87/113757441504aee3808cb422990ed7c8bcc2d53a6779c66c5adef0942939/coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac", size = 249151, upload-time = "2025-11-18T13:33:36.135Z" }, 104 | { url = "https://files.pythonhosted.org/packages/d9/1d/9529d9bd44049b6b05bb319c03a3a7e4b0a8a802d28fa348ad407e10706d/coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d", size = 251667, upload-time = "2025-11-18T13:33:37.996Z" }, 105 | { url = "https://files.pythonhosted.org/packages/11/bb/567e751c41e9c03dc29d3ce74b8c89a1e3396313e34f255a2a2e8b9ebb56/coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c", size = 253003, upload-time = "2025-11-18T13:33:39.553Z" }, 106 | { url = "https://files.pythonhosted.org/packages/e4/b3/c2cce2d8526a02fb9e9ca14a263ca6fc074449b33a6afa4892838c903528/coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434", size = 249185, upload-time = "2025-11-18T13:33:42.086Z" }, 107 | { url = "https://files.pythonhosted.org/packages/0e/a7/967f93bb66e82c9113c66a8d0b65ecf72fc865adfba5a145f50c7af7e58d/coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc", size = 251025, upload-time = "2025-11-18T13:33:43.634Z" }, 108 | { url = "https://files.pythonhosted.org/packages/b9/b2/f2f6f56337bc1af465d5b2dc1ee7ee2141b8b9272f3bf6213fcbc309a836/coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc", size = 248979, upload-time = "2025-11-18T13:33:46.04Z" }, 109 | { url = "https://files.pythonhosted.org/packages/f4/7a/bf4209f45a4aec09d10a01a57313a46c0e0e8f4c55ff2965467d41a92036/coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e", size = 248800, upload-time = "2025-11-18T13:33:47.546Z" }, 110 | { url = "https://files.pythonhosted.org/packages/b8/b7/1e01b8696fb0521810f60c5bbebf699100d6754183e6cc0679bf2ed76531/coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17", size = 250460, upload-time = "2025-11-18T13:33:49.537Z" }, 111 | { url = "https://files.pythonhosted.org/packages/71/ae/84324fb9cb46c024760e706353d9b771a81b398d117d8c1fe010391c186f/coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933", size = 220533, upload-time = "2025-11-18T13:33:51.16Z" }, 112 | { url = "https://files.pythonhosted.org/packages/e2/71/1033629deb8460a8f97f83e6ac4ca3b93952e2b6f826056684df8275e015/coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe", size = 221348, upload-time = "2025-11-18T13:33:52.776Z" }, 113 | { url = "https://files.pythonhosted.org/packages/0a/5f/ac8107a902f623b0c251abdb749be282dc2ab61854a8a4fcf49e276fce2f/coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d", size = 219922, upload-time = "2025-11-18T13:33:54.316Z" }, 114 | { url = "https://files.pythonhosted.org/packages/79/6e/f27af2d4da367f16077d21ef6fe796c874408219fa6dd3f3efe7751bd910/coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d", size = 218511, upload-time = "2025-11-18T13:33:56.343Z" }, 115 | { url = "https://files.pythonhosted.org/packages/67/dd/65fd874aa460c30da78f9d259400d8e6a4ef457d61ab052fd248f0050558/coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03", size = 218771, upload-time = "2025-11-18T13:33:57.966Z" }, 116 | { url = "https://files.pythonhosted.org/packages/55/e0/7c6b71d327d8068cb79c05f8f45bf1b6145f7a0de23bbebe63578fe5240a/coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9", size = 260151, upload-time = "2025-11-18T13:33:59.597Z" }, 117 | { url = "https://files.pythonhosted.org/packages/49/ce/4697457d58285b7200de6b46d606ea71066c6e674571a946a6ea908fb588/coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6", size = 262257, upload-time = "2025-11-18T13:34:01.166Z" }, 118 | { url = "https://files.pythonhosted.org/packages/2f/33/acbc6e447aee4ceba88c15528dbe04a35fb4d67b59d393d2e0d6f1e242c1/coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339", size = 264671, upload-time = "2025-11-18T13:34:02.795Z" }, 119 | { url = "https://files.pythonhosted.org/packages/87/ec/e2822a795c1ed44d569980097be839c5e734d4c0c1119ef8e0a073496a30/coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e", size = 259231, upload-time = "2025-11-18T13:34:04.397Z" }, 120 | { url = "https://files.pythonhosted.org/packages/72/c5/a7ec5395bb4a49c9b7ad97e63f0c92f6bf4a9e006b1393555a02dae75f16/coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13", size = 262137, upload-time = "2025-11-18T13:34:06.068Z" }, 121 | { url = "https://files.pythonhosted.org/packages/67/0c/02c08858b764129f4ecb8e316684272972e60777ae986f3865b10940bdd6/coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f", size = 259745, upload-time = "2025-11-18T13:34:08.04Z" }, 122 | { url = "https://files.pythonhosted.org/packages/5a/04/4fd32b7084505f3829a8fe45c1a74a7a728cb251aaadbe3bec04abcef06d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1", size = 258570, upload-time = "2025-11-18T13:34:09.676Z" }, 123 | { url = "https://files.pythonhosted.org/packages/48/35/2365e37c90df4f5342c4fa202223744119fe31264ee2924f09f074ea9b6d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b", size = 260899, upload-time = "2025-11-18T13:34:11.259Z" }, 124 | { url = "https://files.pythonhosted.org/packages/05/56/26ab0464ca733fa325e8e71455c58c1c374ce30f7c04cebb88eabb037b18/coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a", size = 221313, upload-time = "2025-11-18T13:34:12.863Z" }, 125 | { url = "https://files.pythonhosted.org/packages/da/1c/017a3e1113ed34d998b27d2c6dba08a9e7cb97d362f0ec988fcd873dcf81/coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291", size = 222423, upload-time = "2025-11-18T13:34:15.14Z" }, 126 | { url = "https://files.pythonhosted.org/packages/4c/36/bcc504fdd5169301b52568802bb1b9cdde2e27a01d39fbb3b4b508ab7c2c/coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384", size = 220459, upload-time = "2025-11-18T13:34:17.222Z" }, 127 | { url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" }, 128 | ] 129 | 130 | [package.optional-dependencies] 131 | toml = [ 132 | { name = "tomli", marker = "python_full_version <= '3.11'" }, 133 | ] 134 | 135 | [[package]] 136 | name = "django" 137 | version = "5.2.9" 138 | source = { registry = "https://pypi.org/simple" } 139 | resolution-markers = [ 140 | "python_full_version == '3.11.*'", 141 | "python_full_version < '3.11'", 142 | ] 143 | dependencies = [ 144 | { name = "asgiref", marker = "python_full_version < '3.12'" }, 145 | { name = "sqlparse", marker = "python_full_version < '3.12'" }, 146 | { name = "tzdata", marker = "python_full_version < '3.12' and sys_platform == 'win32'" }, 147 | ] 148 | sdist = { url = "https://files.pythonhosted.org/packages/eb/1c/188ce85ee380f714b704283013434976df8d3a2df8e735221a02605b6794/django-5.2.9.tar.gz", hash = "sha256:16b5ccfc5e8c27e6c0561af551d2ea32852d7352c67d452ae3e76b4f6b2ca495", size = 10848762, upload-time = "2025-12-02T14:01:08.418Z" } 149 | wheels = [ 150 | { url = "https://files.pythonhosted.org/packages/17/b0/7f42bfc38b8f19b78546d47147e083ed06e12fc29c42da95655e0962c6c2/django-5.2.9-py3-none-any.whl", hash = "sha256:3a4ea88a70370557ab1930b332fd2887a9f48654261cdffda663fef5976bb00a", size = 8290652, upload-time = "2025-12-02T14:01:03.485Z" }, 151 | ] 152 | 153 | [[package]] 154 | name = "django" 155 | version = "6.0" 156 | source = { registry = "https://pypi.org/simple" } 157 | resolution-markers = [ 158 | "python_full_version >= '3.12'", 159 | ] 160 | dependencies = [ 161 | { name = "asgiref", marker = "python_full_version >= '3.12'" }, 162 | { name = "sqlparse", marker = "python_full_version >= '3.12'" }, 163 | { name = "tzdata", marker = "python_full_version >= '3.12' and sys_platform == 'win32'" }, 164 | ] 165 | sdist = { url = "https://files.pythonhosted.org/packages/15/75/19762bfc4ea556c303d9af8e36f0cd910ab17dff6c8774644314427a2120/django-6.0.tar.gz", hash = "sha256:7b0c1f50c0759bbe6331c6a39c89ae022a84672674aeda908784617ef47d8e26", size = 10932418, upload-time = "2025-12-03T16:26:21.878Z" } 166 | wheels = [ 167 | { url = "https://files.pythonhosted.org/packages/d7/ae/f19e24789a5ad852670d6885f5480f5e5895576945fcc01817dfd9bc002a/django-6.0-py3-none-any.whl", hash = "sha256:1cc2c7344303bbfb7ba5070487c17f7fc0b7174bbb0a38cebf03c675f5f19b6d", size = 8339181, upload-time = "2025-12-03T16:26:16.231Z" }, 168 | ] 169 | 170 | [[package]] 171 | name = "exceptiongroup" 172 | version = "1.3.1" 173 | source = { registry = "https://pypi.org/simple" } 174 | dependencies = [ 175 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, 176 | ] 177 | sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } 178 | wheels = [ 179 | { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, 180 | ] 181 | 182 | [[package]] 183 | name = "execnet" 184 | version = "2.1.2" 185 | source = { registry = "https://pypi.org/simple" } 186 | sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } 187 | wheels = [ 188 | { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, 189 | ] 190 | 191 | [[package]] 192 | name = "factory-boy" 193 | version = "3.3.3" 194 | source = { registry = "https://pypi.org/simple" } 195 | dependencies = [ 196 | { name = "faker" }, 197 | ] 198 | sdist = { url = "https://files.pythonhosted.org/packages/ba/98/75cacae9945f67cfe323829fc2ac451f64517a8a330b572a06a323997065/factory_boy-3.3.3.tar.gz", hash = "sha256:866862d226128dfac7f2b4160287e899daf54f2612778327dd03d0e2cb1e3d03", size = 164146, upload-time = "2025-02-03T09:49:04.433Z" } 199 | wheels = [ 200 | { url = "https://files.pythonhosted.org/packages/27/8d/2bc5f5546ff2ccb3f7de06742853483ab75bf74f36a92254702f8baecc79/factory_boy-3.3.3-py2.py3-none-any.whl", hash = "sha256:1c39e3289f7e667c4285433f305f8d506efc2fe9c73aaea4151ebd5cdea394fc", size = 37036, upload-time = "2025-02-03T09:49:01.659Z" }, 201 | ] 202 | 203 | [[package]] 204 | name = "faker" 205 | version = "38.2.0" 206 | source = { registry = "https://pypi.org/simple" } 207 | dependencies = [ 208 | { name = "tzdata" }, 209 | ] 210 | sdist = { url = "https://files.pythonhosted.org/packages/64/27/022d4dbd4c20567b4c294f79a133cc2f05240ea61e0d515ead18c995c249/faker-38.2.0.tar.gz", hash = "sha256:20672803db9c7cb97f9b56c18c54b915b6f1d8991f63d1d673642dc43f5ce7ab", size = 1941469, upload-time = "2025-11-19T16:37:31.892Z" } 211 | wheels = [ 212 | { url = "https://files.pythonhosted.org/packages/17/93/00c94d45f55c336434a15f98d906387e87ce28f9918e4444829a8fda432d/faker-38.2.0-py3-none-any.whl", hash = "sha256:35fe4a0a79dee0dc4103a6083ee9224941e7d3594811a50e3969e547b0d2ee65", size = 1980505, upload-time = "2025-11-19T16:37:30.208Z" }, 213 | ] 214 | 215 | [[package]] 216 | name = "iniconfig" 217 | version = "2.3.0" 218 | source = { registry = "https://pypi.org/simple" } 219 | sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } 220 | wheels = [ 221 | { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, 222 | ] 223 | 224 | [[package]] 225 | name = "model-bakery" 226 | version = "1.20.5" 227 | source = { registry = "https://pypi.org/simple" } 228 | dependencies = [ 229 | { name = "django", version = "5.2.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, 230 | { name = "django", version = "6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, 231 | ] 232 | sdist = { url = "https://files.pythonhosted.org/packages/bf/73/24854c5053c852201b4799e7837060496d1418a28488a90a299e8d9c618b/model_bakery-1.20.5.tar.gz", hash = "sha256:107b3efb8889baac83cae0e2d81465903b69a70eeb99ecfd0929d959a653ab90", size = 21332, upload-time = "2025-06-07T10:21:47.727Z" } 233 | wheels = [ 234 | { url = "https://files.pythonhosted.org/packages/13/4b/157c1113e317f79a257b4dfe0607dbab7f57bec67a34d053588dfb8945ac/model_bakery-1.20.5-py3-none-any.whl", hash = "sha256:796e0b7fa6bf2acc09feaadce40c6bcc13e5b55c5bdff9f76e87ceb64f736070", size = 24292, upload-time = "2025-06-07T10:21:46.438Z" }, 235 | ] 236 | 237 | [[package]] 238 | name = "numpy" 239 | version = "2.2.6" 240 | source = { registry = "https://pypi.org/simple" } 241 | resolution-markers = [ 242 | "python_full_version < '3.11'", 243 | ] 244 | sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } 245 | wheels = [ 246 | { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, 247 | { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, 248 | { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, 249 | { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, 250 | { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, 251 | { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, 252 | { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, 253 | { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, 254 | { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, 255 | { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, 256 | { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, 257 | { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, 258 | { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, 259 | { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, 260 | { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, 261 | { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, 262 | { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, 263 | { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, 264 | { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, 265 | { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, 266 | { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, 267 | { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, 268 | { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, 269 | { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, 270 | { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, 271 | { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, 272 | { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, 273 | { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, 274 | { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, 275 | { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, 276 | { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, 277 | { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, 278 | { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, 279 | { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, 280 | { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, 281 | { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, 282 | { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, 283 | { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, 284 | { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, 285 | { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, 286 | { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, 287 | { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, 288 | { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, 289 | { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, 290 | { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, 291 | { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, 292 | { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, 293 | { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, 294 | { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, 295 | { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, 296 | { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, 297 | { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, 298 | { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, 299 | { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, 300 | ] 301 | 302 | [[package]] 303 | name = "numpy" 304 | version = "2.3.5" 305 | source = { registry = "https://pypi.org/simple" } 306 | resolution-markers = [ 307 | "python_full_version >= '3.12'", 308 | "python_full_version == '3.11.*'", 309 | ] 310 | sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" } 311 | wheels = [ 312 | { url = "https://files.pythonhosted.org/packages/43/77/84dd1d2e34d7e2792a236ba180b5e8fcc1e3e414e761ce0253f63d7f572e/numpy-2.3.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de5672f4a7b200c15a4127042170a694d4df43c992948f5e1af57f0174beed10", size = 17034641, upload-time = "2025-11-16T22:49:19.336Z" }, 313 | { url = "https://files.pythonhosted.org/packages/2a/ea/25e26fa5837106cde46ae7d0b667e20f69cbbc0efd64cba8221411ab26ae/numpy-2.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acfd89508504a19ed06ef963ad544ec6664518c863436306153e13e94605c218", size = 12528324, upload-time = "2025-11-16T22:49:22.582Z" }, 314 | { url = "https://files.pythonhosted.org/packages/4d/1a/e85f0eea4cf03d6a0228f5c0256b53f2df4bc794706e7df019fc622e47f1/numpy-2.3.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ffe22d2b05504f786c867c8395de703937f934272eb67586817b46188b4ded6d", size = 5356872, upload-time = "2025-11-16T22:49:25.408Z" }, 315 | { url = "https://files.pythonhosted.org/packages/5c/bb/35ef04afd567f4c989c2060cde39211e4ac5357155c1833bcd1166055c61/numpy-2.3.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:872a5cf366aec6bb1147336480fef14c9164b154aeb6542327de4970282cd2f5", size = 6893148, upload-time = "2025-11-16T22:49:27.549Z" }, 316 | { url = "https://files.pythonhosted.org/packages/f2/2b/05bbeb06e2dff5eab512dfc678b1cc5ee94d8ac5956a0885c64b6b26252b/numpy-2.3.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3095bdb8dd297e5920b010e96134ed91d852d81d490e787beca7e35ae1d89cf7", size = 14557282, upload-time = "2025-11-16T22:49:30.964Z" }, 317 | { url = "https://files.pythonhosted.org/packages/65/fb/2b23769462b34398d9326081fad5655198fcf18966fcb1f1e49db44fbf31/numpy-2.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cba086a43d54ca804ce711b2a940b16e452807acebe7852ff327f1ecd49b0d4", size = 16897903, upload-time = "2025-11-16T22:49:34.191Z" }, 318 | { url = "https://files.pythonhosted.org/packages/ac/14/085f4cf05fc3f1e8aa95e85404e984ffca9b2275a5dc2b1aae18a67538b8/numpy-2.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cf9b429b21df6b99f4dee7a1218b8b7ffbbe7df8764dc0bd60ce8a0708fed1e", size = 16341672, upload-time = "2025-11-16T22:49:37.2Z" }, 319 | { url = "https://files.pythonhosted.org/packages/6f/3b/1f73994904142b2aa290449b3bb99772477b5fd94d787093e4f24f5af763/numpy-2.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:396084a36abdb603546b119d96528c2f6263921c50df3c8fd7cb28873a237748", size = 18838896, upload-time = "2025-11-16T22:49:39.727Z" }, 320 | { url = "https://files.pythonhosted.org/packages/cd/b9/cf6649b2124f288309ffc353070792caf42ad69047dcc60da85ee85fea58/numpy-2.3.5-cp311-cp311-win32.whl", hash = "sha256:b0c7088a73aef3d687c4deef8452a3ac7c1be4e29ed8bf3b366c8111128ac60c", size = 6563608, upload-time = "2025-11-16T22:49:42.079Z" }, 321 | { url = "https://files.pythonhosted.org/packages/aa/44/9fe81ae1dcc29c531843852e2874080dc441338574ccc4306b39e2ff6e59/numpy-2.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:a414504bef8945eae5f2d7cb7be2d4af77c5d1cb5e20b296c2c25b61dff2900c", size = 13078442, upload-time = "2025-11-16T22:49:43.99Z" }, 322 | { url = "https://files.pythonhosted.org/packages/6d/a7/f99a41553d2da82a20a2f22e93c94f928e4490bb447c9ff3c4ff230581d3/numpy-2.3.5-cp311-cp311-win_arm64.whl", hash = "sha256:0cd00b7b36e35398fa2d16af7b907b65304ef8bb4817a550e06e5012929830fa", size = 10458555, upload-time = "2025-11-16T22:49:47.092Z" }, 323 | { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873, upload-time = "2025-11-16T22:49:49.84Z" }, 324 | { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838, upload-time = "2025-11-16T22:49:52.863Z" }, 325 | { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378, upload-time = "2025-11-16T22:49:55.055Z" }, 326 | { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559, upload-time = "2025-11-16T22:49:57.371Z" }, 327 | { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702, upload-time = "2025-11-16T22:49:59.632Z" }, 328 | { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086, upload-time = "2025-11-16T22:50:02.127Z" }, 329 | { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985, upload-time = "2025-11-16T22:50:04.536Z" }, 330 | { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976, upload-time = "2025-11-16T22:50:07.557Z" }, 331 | { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274, upload-time = "2025-11-16T22:50:10.746Z" }, 332 | { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922, upload-time = "2025-11-16T22:50:12.811Z" }, 333 | { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667, upload-time = "2025-11-16T22:50:16.16Z" }, 334 | { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" }, 335 | { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" }, 336 | { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" }, 337 | { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" }, 338 | { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" }, 339 | { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" }, 340 | { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" }, 341 | { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" }, 342 | { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" }, 343 | { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" }, 344 | { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" }, 345 | { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" }, 346 | { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" }, 347 | { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" }, 348 | { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" }, 349 | { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" }, 350 | { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" }, 351 | { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" }, 352 | { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" }, 353 | { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" }, 354 | { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" }, 355 | { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" }, 356 | { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706, upload-time = "2025-11-16T22:51:19.558Z" }, 357 | { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507, upload-time = "2025-11-16T22:51:22.492Z" }, 358 | { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049, upload-time = "2025-11-16T22:51:25.171Z" }, 359 | { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603, upload-time = "2025-11-16T22:51:27Z" }, 360 | { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696, upload-time = "2025-11-16T22:51:29.402Z" }, 361 | { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350, upload-time = "2025-11-16T22:51:32.167Z" }, 362 | { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190, upload-time = "2025-11-16T22:51:35.403Z" }, 363 | { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749, upload-time = "2025-11-16T22:51:39.698Z" }, 364 | { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432, upload-time = "2025-11-16T22:51:42.476Z" }, 365 | { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388, upload-time = "2025-11-16T22:51:45.275Z" }, 366 | { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651, upload-time = "2025-11-16T22:51:47.749Z" }, 367 | { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503, upload-time = "2025-11-16T22:51:50.443Z" }, 368 | { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612, upload-time = "2025-11-16T22:51:53.609Z" }, 369 | { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042, upload-time = "2025-11-16T22:51:56.213Z" }, 370 | { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502, upload-time = "2025-11-16T22:51:58.584Z" }, 371 | { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962, upload-time = "2025-11-16T22:52:01.698Z" }, 372 | { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054, upload-time = "2025-11-16T22:52:04.267Z" }, 373 | { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613, upload-time = "2025-11-16T22:52:08.651Z" }, 374 | { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147, upload-time = "2025-11-16T22:52:11.453Z" }, 375 | { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806, upload-time = "2025-11-16T22:52:14.641Z" }, 376 | { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760, upload-time = "2025-11-16T22:52:17.975Z" }, 377 | { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" }, 378 | { url = "https://files.pythonhosted.org/packages/c6/65/f9dea8e109371ade9c782b4e4756a82edf9d3366bca495d84d79859a0b79/numpy-2.3.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f0963b55cdd70fad460fa4c1341f12f976bb26cb66021a5580329bd498988310", size = 16910689, upload-time = "2025-11-16T22:52:23.247Z" }, 379 | { url = "https://files.pythonhosted.org/packages/00/4f/edb00032a8fb92ec0a679d3830368355da91a69cab6f3e9c21b64d0bb986/numpy-2.3.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4255143f5160d0de972d28c8f9665d882b5f61309d8362fdd3e103cf7bf010c", size = 12457053, upload-time = "2025-11-16T22:52:26.367Z" }, 380 | { url = "https://files.pythonhosted.org/packages/16/a4/e8a53b5abd500a63836a29ebe145fc1ab1f2eefe1cfe59276020373ae0aa/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:a4b9159734b326535f4dd01d947f919c6eefd2d9827466a696c44ced82dfbc18", size = 5285635, upload-time = "2025-11-16T22:52:29.266Z" }, 381 | { url = "https://files.pythonhosted.org/packages/a3/2f/37eeb9014d9c8b3e9c55bc599c68263ca44fdbc12a93e45a21d1d56df737/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2feae0d2c91d46e59fcd62784a3a83b3fb677fead592ce51b5a6fbb4f95965ff", size = 6801770, upload-time = "2025-11-16T22:52:31.421Z" }, 382 | { url = "https://files.pythonhosted.org/packages/7d/e4/68d2f474df2cb671b2b6c2986a02e520671295647dad82484cde80ca427b/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffac52f28a7849ad7576293c0cb7b9f08304e8f7d738a8cb8a90ec4c55a998eb", size = 14391768, upload-time = "2025-11-16T22:52:33.593Z" }, 383 | { url = "https://files.pythonhosted.org/packages/b8/50/94ccd8a2b141cb50651fddd4f6a48874acb3c91c8f0842b08a6afc4b0b21/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63c0e9e7eea69588479ebf4a8a270d5ac22763cc5854e9a7eae952a3908103f7", size = 16729263, upload-time = "2025-11-16T22:52:36.369Z" }, 384 | { url = "https://files.pythonhosted.org/packages/2d/ee/346fa473e666fe14c52fcdd19ec2424157290a032d4c41f98127bfb31ac7/numpy-2.3.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f16417ec91f12f814b10bafe79ef77e70113a2f5f7018640e7425ff979253425", size = 12967213, upload-time = "2025-11-16T22:52:39.38Z" }, 385 | ] 386 | 387 | [[package]] 388 | name = "packaging" 389 | version = "25.0" 390 | source = { registry = "https://pypi.org/simple" } 391 | sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } 392 | wheels = [ 393 | { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, 394 | ] 395 | 396 | [[package]] 397 | name = "pluggy" 398 | version = "1.6.0" 399 | source = { registry = "https://pypi.org/simple" } 400 | sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } 401 | wheels = [ 402 | { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, 403 | ] 404 | 405 | [[package]] 406 | name = "pygments" 407 | version = "2.19.2" 408 | source = { registry = "https://pypi.org/simple" } 409 | sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } 410 | wheels = [ 411 | { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, 412 | ] 413 | 414 | [[package]] 415 | name = "pytest" 416 | version = "9.0.2" 417 | source = { registry = "https://pypi.org/simple" } 418 | dependencies = [ 419 | { name = "colorama", marker = "sys_platform == 'win32'" }, 420 | { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, 421 | { name = "iniconfig" }, 422 | { name = "packaging" }, 423 | { name = "pluggy" }, 424 | { name = "pygments" }, 425 | { name = "tomli", marker = "python_full_version < '3.11'" }, 426 | ] 427 | sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } 428 | wheels = [ 429 | { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, 430 | ] 431 | 432 | [[package]] 433 | name = "pytest-randomly" 434 | version = "4.0.1" 435 | source = { editable = "." } 436 | dependencies = [ 437 | { name = "pytest" }, 438 | ] 439 | 440 | [package.dev-dependencies] 441 | test = [ 442 | { name = "coverage", extra = ["toml"] }, 443 | { name = "factory-boy" }, 444 | { name = "faker" }, 445 | { name = "model-bakery" }, 446 | { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, 447 | { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, 448 | { name = "pytest" }, 449 | { name = "pytest-xdist" }, 450 | ] 451 | 452 | [package.metadata] 453 | requires-dist = [{ name = "pytest" }] 454 | 455 | [package.metadata.requires-dev] 456 | test = [ 457 | { name = "coverage", extras = ["toml"] }, 458 | { name = "factory-boy" }, 459 | { name = "faker" }, 460 | { name = "model-bakery", specifier = ">=1.13" }, 461 | { name = "numpy" }, 462 | { name = "pytest" }, 463 | { name = "pytest-xdist" }, 464 | ] 465 | 466 | [[package]] 467 | name = "pytest-xdist" 468 | version = "3.8.0" 469 | source = { registry = "https://pypi.org/simple" } 470 | dependencies = [ 471 | { name = "execnet" }, 472 | { name = "pytest" }, 473 | ] 474 | sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } 475 | wheels = [ 476 | { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, 477 | ] 478 | 479 | [[package]] 480 | name = "sqlparse" 481 | version = "0.5.4" 482 | source = { registry = "https://pypi.org/simple" } 483 | sdist = { url = "https://files.pythonhosted.org/packages/18/67/701f86b28d63b2086de47c942eccf8ca2208b3be69715a1119a4e384415a/sqlparse-0.5.4.tar.gz", hash = "sha256:4396a7d3cf1cd679c1be976cf3dc6e0a51d0111e87787e7a8d780e7d5a998f9e", size = 120112, upload-time = "2025-11-28T07:10:18.377Z" } 484 | wheels = [ 485 | { url = "https://files.pythonhosted.org/packages/25/70/001ee337f7aa888fb2e3f5fd7592a6afc5283adb1ed44ce8df5764070f22/sqlparse-0.5.4-py3-none-any.whl", hash = "sha256:99a9f0314977b76d776a0fcb8554de91b9bb8a18560631d6bc48721d07023dcb", size = 45933, upload-time = "2025-11-28T07:10:19.73Z" }, 486 | ] 487 | 488 | [[package]] 489 | name = "tomli" 490 | version = "2.3.0" 491 | source = { registry = "https://pypi.org/simple" } 492 | sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } 493 | wheels = [ 494 | { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, 495 | { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, 496 | { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, 497 | { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, 498 | { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, 499 | { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, 500 | { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, 501 | { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, 502 | { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, 503 | { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, 504 | { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, 505 | { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, 506 | { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, 507 | { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, 508 | { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, 509 | { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, 510 | { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" }, 511 | { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" }, 512 | { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, 513 | { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, 514 | { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, 515 | { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, 516 | { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, 517 | { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, 518 | { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, 519 | { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, 520 | { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, 521 | { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, 522 | { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, 523 | { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, 524 | { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, 525 | { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, 526 | { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, 527 | { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, 528 | { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, 529 | { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, 530 | { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, 531 | { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, 532 | { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, 533 | { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, 534 | { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, 535 | ] 536 | 537 | [[package]] 538 | name = "typing-extensions" 539 | version = "4.15.0" 540 | source = { registry = "https://pypi.org/simple" } 541 | sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } 542 | wheels = [ 543 | { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, 544 | ] 545 | 546 | [[package]] 547 | name = "tzdata" 548 | version = "2025.2" 549 | source = { registry = "https://pypi.org/simple" } 550 | sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } 551 | wheels = [ 552 | { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, 553 | ] 554 | --------------------------------------------------------------------------------