From 3cb9ce00eef8bc62b2b000efeb6f0e45c4e7b7fa Mon Sep 17 00:00:00 2001 From: "John M. Kuchta" Date: Wed, 8 Jul 2026 21:17:41 -0700 Subject: [PATCH 01/11] fix(deps): bump idna 3.10 -> 3.18 (GHSA-65pc-fj4g-8rjx) Patches idna.encode() bypass of the CVE-2024-3651 fix (Dependabot alert #85). Co-Authored-By: Claude Opus 4.8 (1M context) --- uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index a9e24b8a..e33c5ea4 100644 --- a/uv.lock +++ b/uv.lock @@ -276,11 +276,11 @@ wheels = [ [[package]] name = "idna" -version = "3.10" +version = "3.18" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, ] [[package]] From 963d77d7235df53eda545798204bcb1466f127e7 Mon Sep 17 00:00:00 2001 From: "John M. Kuchta" Date: Wed, 8 Jul 2026 21:50:27 -0700 Subject: [PATCH 02/11] docs: overhaul README/generator readme; fix stale aiohttp comments Rework README into a value-forward feature list, add Releases (GA vs beta) and Smart flow sections, a nav row, and a docs index. Collapse the duplicated AsyncIO usage steps into one runnable example. Fix anachronisms (Python 2/easy_install, master->main URLs, broken link) and switch endpoint->operation per Cisco naming. Trim the generator readme and point it at published betas. Replace two stale aiohttp references in async_.py with httpx (comment + docstring); no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 255 ++++++++++++++++++++++----------------- generator/readme.md | 22 ++-- meraki/session/async_.py | 4 +- 3 files changed, 153 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index d2a6d317..c7f5a2ab 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,9 @@ # Meraki Dashboard API Python Library -The Meraki Dashboard API Python library provides all current -Meraki [dashboard API](https://developer.cisco.com/meraki/api-v1/) calls to interface with the Cisco Meraki -cloud-managed platform. Meraki generates the library based on dashboard API's OpenAPI spec to keep it up to date with -the latest API releases, and provides the full source code for the library including the tools used to generate the -library, if you are participating in the Early Access program or would like to contribute to the development of the -library. Meraki welcomes constructive pull requests that maintain backwards compatibility with prior versions. The -library requires Python 3.10+, receives support from the community, and you can install it via +A Python client for the Cisco Meraki [dashboard API](https://developer.cisco.com/meraki/api-v1/), covering every +current operation. It's generated from the API's OpenAPI spec, so it tracks the latest releases automatically. The full +source, including the generator, is here for Early Access participants and contributors; pull requests that maintain +backwards compatibility are welcome. Requires Python 3.10+, community-supported, installable via [PyPI](https://pypi.org/project/meraki/): pip install --upgrade meraki @@ -17,25 +14,43 @@ Or with [uv](https://docs.astral.sh/uv/): If you participate in [our Early Access program](https://community.meraki.com/t5/Developers-APIs/UPDATED-Beta-testing-with-the-Meraki-Developer-Early-Access/m-p/145344#M5808) -and would like to use early access features via the library, -you'll [find instructions in the generator readme](https://github.com/meraki/dashboard-api-python/tree/main/generator#readme). +and would like to use early access features via the library, you have two options: install a published +[beta release](#releases) from PyPI (`pip install meraki==bN`), or, if you need a library matched to your own +org's spec, [generate one yourself](https://github.com/meraki/dashboard-api-python/tree/main/generator#readme). + +### [Features](#features) · [Releases](#releases) · [Usage](#usage) · [Smart flow](#smart-flow-rate-limiting) · [AsyncIO](#asyncio) · [Versioning](VERSIONING.md) · [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md) ## Features -While you can make direct HTTP requests to dashboard API in any programming language or REST API client, using a client -library can make it easier for you to focus on your specific use case, without the overhead of having to write functions -to handle the dashboard API calls. The Python library can also take care of error handling, logging, retries, and other -convenient processes and options for you automatically. - -* Support for all API endpoints, as it uses the [OpenAPI specification](https://api.meraki.com/api/v1/openapiSpec) to - generate source code -* Log all API requests made to a local file as well as on-screen console -* Automatic retries upon 429 rate limit errors, using - the [`Retry-After` field](https://developer.cisco.com/meraki/api-v1/#!rate-limit) within response headers -* Get all (or a specified number of) pages of data with built-in pagination control -* Tweak settings such as maximum retries, certificate path, suppress logging, and other options -* Simulate POST/PUT/DELETE calls to preview first, so that network configuration does not get changed -* Optional kwarg validation that warns when unrecognized keyword arguments are silently ignored +You could hit the dashboard API with raw HTTP in any language. But then you own the rate-limit math, the retry loops, +the pagination bookkeeping, the auth headers, and the error handling, for every one of the hundreds of operations, and +you re-own it every time the API changes. This library does all of that for you, and stays current automatically because +it's generated from the API's own OpenAPI spec. + +What you get out of the box: + +- **Complete, always-current operation coverage** — every dashboard API operation, generated straight from the + [OpenAPI specification](https://api.meraki.com/api/v1/openapiSpec), so new operations land as the API ships them +- **Proactive rate limiting ("smart flow")** — per-org token buckets keep you under Meraki's 10 req/s org limit and + 100 req/s source-IP limit _before_ you get throttled, turning 429-and-retry churn into steady throughput. On by + default, zero config. [Details below.](#smart-flow-rate-limiting) +- **Automatic retries** — 429s honor the [`Retry-After`](https://developer.cisco.com/meraki/api-v1/#!rate-limit) + header; transient 5xx and select 4xx (network-delete/action-batch concurrency) back off and retry so your script + doesn't fall over on a blip +- **Built-in pagination** — pull all pages, or a specific number, with one call; no manual Link-header walking +- **Sync and async** — a synchronous client and a fully `async`/`await` client + ([AsyncIO](#asyncio)) sharing the same interface, so you scale up concurrency without rewriting your logic +- **Modern HTTP stack** — built on [httpx](https://www.python-httpx.org/) (not `requests`/`aiohttp`), a unified, + type-annotated, HTTP/2-capable backend powering both the sync and async clients +- **Early access via beta releases** — opt into beta builds to use API operations before they reach GA, in step with + Meraki's [Early Access program](https://community.meraki.com/t5/Developers-APIs/UPDATED-Beta-testing-with-the-Meraki-Developer-Early-Access/m-p/145344#M5808). [Details below.](#releases) +- **Dry-run mode** — simulate POST/PUT/DELETE calls to preview changes without touching your network configuration +- **Logging you can trust** — every request logged to file and console, with X-Request-Id captured on failures for + fast support escalation to Meraki +- **Kwarg validation** — optional typo protection that warns when an unrecognized keyword argument would otherwise be + silently ignored, catching bugs before they ship +- **Tunable everything** — retries, timeouts, certificate path, proxy, logging verbosity, and more, all configurable + per client or via environment ## Setup @@ -45,66 +60,75 @@ convenient processes and options for you automatically. 2. Keep your API key safe and secure, as it is similar to a password for your dashboard. If publishing your Python code to a wider audience, please research secure handling of API keys. -3. Install the latest version of [Python 3](ttps://wiki.python.org/moin/BeginnersGuide/NonProgrammers) +3. Install [Python 3.10 or later](https://wiki.python.org/moin/BeginnersGuide/NonProgrammers) -4. Use _pip_ (or an alternative such as _easy_install_) to install the library from the +4. Use _pip_ to install the library from the Python [Package Index](https://pypi.org/project/meraki/): - * `pip install meraki` - * If you have both Python3 and Python2 installed, you may need to use `pip3` (so `pip3 install meraki`) along - with `python3` on your system - * If _meraki_ was previously installed, you can upgrade to the latest non-beta release - with `pip install --upgrade meraki` - -5. The library supports Meraki dashboard API v1. You can also specify the version of the library when installing with - _pip_: - * See the full [release history](https://pypi.org/project/meraki/#history) to pick the version you want, or - use `pip install meraki==` without including a version number to display the list of available versions - * Versions begin with _1_ (1.0.0b**z** for beta) - * Specify the version you want with the install command; for example: `pip install meraki==1.34.0` - * You can also see the version currently installed with `pip show meraki` - * End-of-life v0 versions of the Python library begin with _0_ (0.**x**.**y**) and are not supported nor - recommended. + - `pip install meraki` + - If _meraki_ was previously installed, you can upgrade to the latest non-beta release + with `pip install --upgrade meraki` + +5. The library supports Meraki dashboard API v1. To install or check a specific version: + - `pip install meraki==4.3.0` installs that version (see the full [release history](https://pypi.org/project/meraki/#history)) + - `pip show meraki` reports the version currently installed + - Picking between stable and beta releases is covered under [Releases](#releases) below + +## Releases + +`pip install --upgrade meraki` gets the latest **stable (GA)** release, which contains only GA operations from the +upstream dashboard API. Stable releases track upstream API minor versions and are published automatically when a new +OpenAPI spec ships. + +**Beta releases** (PEP 440 suffix, e.g. `4.3.0b1`) may also include beta API operations that haven't graduated to GA. +They are published to PyPI but never installed by default; opt in explicitly: + +```shell +pip install meraki==4.3.0b1 +``` + +Both the beta API operations they expose and the SDK surfaces themselves may change in breaking ways between beta releases, without notice. Beta API operations are subject to unannounced change or removal upstream, so upgrading from a beta to a stable release can _remove_ operations that never reached GA. Use a beta release only if you need early-access API operations or unreleased SDK features and accept that trade-off. + +For the full versioning scheme, cadence, and SDK-to-API version mapping, see [VERSIONING.md](VERSIONING.md). ## Usage 1. Export your API key as an [environment variable](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html), for example: - ```shell - export MERAKI_DASHBOARD_API_KEY=YOUR_KEY_HERE - ``` + ```shell + export MERAKI_DASHBOARD_API_KEY=YOUR_KEY_HERE + ``` -2. Alternatively, define your API key as a variable in your source code; this method is not recommended due to its - inherent insecurity. +2. Alternatively, define it as a variable in your source code (not recommended: it's insecure). -3. Single line of code to import and use the library goes at the top of your script: +3. Import the library at the top of your script: - ```python - import meraki - ``` + ```python + import meraki + ``` 4. Instantiate the client (API consumer class), optionally specifying any of the parameters available to set: - ```python - dashboard = meraki.DashboardAPI() - ``` + ```python + dashboard = meraki.DashboardAPI() + ``` 5. Make dashboard API calls in your source code, using the format _client.scope.operation_, where _client_ is the name you defined in the previous step (**dashboard** above), _scope_ is the corresponding scope that represents the first - tag from the OpenAPI spec, and _operation_ is the operation of the API endpoint. For example, to make a call to get - the list of organizations accessible by the API key defined in step 1, use this function call: + tag from the OpenAPI spec, and _operation_ is the operation ID from the OpenAPI spec. For example, to make a call to + get the list of organizations accessible by the API key defined in step 1, use this function call: - ```python - my_orgs = dashboard.organizations.getOrganizations() - ``` + ```python + my_orgs = dashboard.organizations.getOrganizations() + ``` ### Examples You can find fully working example scripts in the **examples** folder. | Script | Purpose | -|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **org_wide_clients.py** | That code collects the clients of all networks, in all orgs to which the key has access. No changes are made, since only GET endpoints are called, and the data is written to local CSV output files. | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **org_wide_clients.py** | That code collects the clients of all networks, in all orgs to which the key has access. No changes are made, since only GET operations are called, and the data is written to local CSV output files. | ### Keyword argument validation @@ -120,84 +144,79 @@ dashboard.networks.updateNetwork(networkId, nme="HQ") This is off by default for backwards compatibility and zero performance overhead in production. -## AsyncIO +## Smart flow rate limiting -**asyncio** is a library to write concurrent code using the **async/await** syntax. Special thanks to Heimo -Stieg ([@coreGreenberet](https://github.com/coreGreenberet)) who has ported the API to asyncio. +The Meraki API enforces two rate limits: **10 requests/second per organization** and **100 requests/second per source +IP**. Exceed either and you get `429` responses. The traditional approach is reactive: send too fast, get a 429, wait +for `Retry-After`, retry. That wastes round-trips, and every 429 you generate also eats into the budget shared by other +applications hitting the same org. -### Installation on macOS +Smart flow is **proactive**. Each org gets its own token bucket, so the SDK paces requests to stay under the limit +_before_ sending, turning 429-and-retry churn into steady throughput. It's **enabled by default** with no code changes +required. -If you use a Mac, then you may need to take -[additional Python installation steps](https://bugs.python.org/issue43404) that aren't required on other platforms. This -is [a limitation of macOS and not the library](https://github.com/meraki/dashboard-api-python/issues/226). This step is -not required on Windows. +Benefits: -### Usage +- **Fewer 429s** — requests are throttled client-side instead of bouncing off the server +- **Faster overall** — no `Retry-After` wait cycles wasted on avoidable rate-limit errors +- **Fairer** — reserves headroom (default 9 of 10 req/s per org) so you don't starve other apps on the same org +- **Zero-config** — org membership is learned automatically from the URLs you already call, and cached to disk + (`~/.meraki/.cache/`) so subsequent runs skip the lookup -The usage is similiar to the sequential version above. However it has has some differences. +Tune it via kwargs on the client (all optional): -1. Export your API key as - an [environment variable](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html), for example: +```python +dashboard = meraki.DashboardAPI( + smart_flow_enabled=True, # default; set False to fall back to 429-retry only + smart_flow_org_rate=9, # max req/s per org (leaves 1 for other apps) + smart_flow_global_rate=100, # max req/s across all orgs (source-IP limit) + smart_flow_cache_mode="lazy", # "lazy" learns as you go; "eager" pre-fetches at init +) +``` - ```shell - export MERAKI_DASHBOARD_API_KEY=YOUR_KEY_HERE - ``` +See [config.py](https://github.com/meraki/dashboard-api-python/blob/main/meraki/config.py) for the full set of smart +flow options and their defaults. -2. Alternatively, define your API key as a variable in your source code; this method is not recommended due to its - inherent insecurity. +## AsyncIO -3. Single line of code to import and use the library goes at the top of your script: +The library ships a fully async client (`meraki.aio.AsyncDashboardAPI`) using **async/await**, alongside the +synchronous client. Original async port by Heimo Stieg ([@coreGreenberet](https://github.com/coreGreenberet)). - ```python - import meraki.aio - ``` +### Usage -4. Instantiate the client (API consumer class), optionally specifying any of the parameters available to set: +Same as the synchronous client, with four differences: import `meraki.aio`, instantiate inside `async with`, `await` +each call, and run it all in an event loop. - ```python - async with meraki.aio.AsyncDashboardAPI() as aiomeraki: - ``` - The **async with** statement is important here to make sure, that the client sessions will be closed after using the - api. +```python +import asyncio +import meraki.aio -5. Make dashboard API calls in your source code, using the format await _client.section.operation_, where _client_ is - the name you defined in the previous step (**aiomeraki** above), _section_ is the corresponding group (or tag from - the OpenAPI spec) from the [API docs](https://developer.cisco.com/meraki/api/#/rest), and _operation_ is the name (or - operation ID from OpenAPI) of the API endpoint. For example, to make a call to get the list of organizations - accessible by the API key defined in step 1, use this function call: - ```python - my_orgs = await aiomeraki.organizations.getOrganizations() - ``` -6. Run everything inside an event loop. +async def main(): + # `async with` ensures the client's sessions are closed on exit + async with meraki.aio.AsyncDashboardAPI() as aiomeraki: + my_orgs = await aiomeraki.organizations.getOrganizations() -```python -import asyncio if __name__ == "__main__": - # replace my_async_entry_point with the name of your entry point method - asyncio.run(my_async_entry_point()) + asyncio.run(main()) ``` ### Examples You can find fully working example scripts in the **examples** folder. -| Script | Purpose | -|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **aio_org_wide_clients.py** | That code is a asyncio port from org_wide_clients.py and collects the clients of all -networks, in all orgs to which the key has access. No changes are made, since only GET endpoints are called, and the -data is written to local CSV output files. | -| **aio_ips2firewall.py** | That code will collect the source IP of security events and creates L7 firewall rules to -block them. `usage: aio_ips2firewall.py [-h] -o ORGANIZATIONS [ORGANIZATIONS ...] [-f FILTER] [-s] [-d DAYS]` | +| Script | Purpose | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **aio_org_wide_clients.py** | An asyncio port of org_wide_clients.py: collects the clients of all networks, in all orgs to which the key has access. No changes are made, since only GET operations are called, and data is written to local CSVs. | +| **aio_ips2firewall.py** | Collects the source IP of security events and creates L7 firewall rules to block them. `usage: aio_ips2firewall.py [-h] -o ORGANIZATIONS [ORGANIZATIONS ...] [-f FILTER] [-s] [-d DAYS]` | ## Note for application developers and ecosystem partners -We're so glad that you're leveraging our Python library. It's best practice to identify your application with every API -request that you make. You can easily do this automatically just by following the format defined -in [config.py](https://github.com/meraki/dashboard-api-python/blob/master/meraki/config.py) and passing the session +Identify your application with every API request by following the format defined +in [config.py](https://github.com/meraki/dashboard-api-python/blob/main/meraki/config.py) and passing the session kwarg: -``` Python +```Python MERAKI_PYTHON_SDK_CALLER ``` @@ -216,12 +235,22 @@ This project uses [uv](https://docs.astral.sh/uv/) for dependency management and 2. Install dev dependencies: - uv sync + uv sync 3. Run tests: - uv run pytest + uv run pytest 4. If you're working with the generator, install its additional dependencies: - uv sync --group generator + uv sync --group generator + +## Further documentation + +| Doc | Covers | +| ------------------------------------------ | ------------------------------------------------- | +| [CHANGELOG.md](CHANGELOG.md) | Release notes per version | +| [VERSIONING.md](VERSIONING.md) | Versioning scheme, GA vs beta, SDK-to-API mapping | +| [CONTRIBUTING.md](CONTRIBUTING.md) | How to contribute and add changelog fragments | +| [SECURITY.md](SECURITY.md) | Reporting security issues | +| [generator/README.md](generator/README.md) | Regenerating the library and Early Access usage | diff --git a/generator/readme.md b/generator/readme.md index 4540b7ba..8689ef6a 100644 --- a/generator/readme.md +++ b/generator/readme.md @@ -1,10 +1,9 @@ # Generating the Meraki Dashboard API Python Library -Generally speaking, you will not need to generate this yourself. Simply use the official PyPI package -via `pip install --upgrade meraki`. +Most users don't need this: just `pip install --upgrade meraki`, or a [published beta +release](https://github.com/meraki/dashboard-api-python#releases) for early-access operations. -However, if you participate in Early Access features, you may want to generate a library to match your org's spec. In -which case, follow along. +Generate the library yourself only when you need it matched to your own org's spec. Follow along below. > **NB:** The generator requires Python 3.11 or later. @@ -16,8 +15,8 @@ which case, follow along. uv sync --group generator ``` -4. *Optional:* If you want to work with beta endpoints, then - first [review the warnings, and then opt one of your orgs into the Early API Access program](https://community.meraki.com/t5/Developers-APIs/UPDATED-Beta-testing-with-the-Meraki-Developer-Early-Access/m-p/145344#M5808). +4. *Optional:* To work with beta operations, first [review the warnings and opt one of your orgs into the Early API + Access program](https://community.meraki.com/t5/Developers-APIs/UPDATED-Beta-testing-with-the-Meraki-Developer-Early-Access/m-p/145344#M5808). 5. Run the generator: ```shell @@ -26,14 +25,11 @@ which case, follow along. Making these replacements: * Replace `YOUR_ORG_ID` with the org ID you want to use as reference. Use the one opted into Early API access if you - want the beta endpoints. + want the beta operations. * Replace `YOUR_API_KEY` with an API key that has org admin privileges on that org. * NB: Your local system may require minor syntax tweaks (e.g. Windows may require you prepend `generate_library.py` with `.\`) -6. You will now have a `meraki` module folder inside `generator`, which you can locally reference in your scripts. - Simply copy the `meraki` folder to those projects which require it. -7. In some cases, if you've already installed the official library, your scripts may prefer that one over the local - folder. If that happens, then calls to early access endpoints will fail. So, if necessary, uninstall any instances of - the meraki package that may have been installed in your venv or system, or replace the version installed in your venv - with that which you generated here. +6. You now have a `meraki` module folder inside `generator`. Copy it into any project that needs it. +7. If the official `meraki` package is also installed, your scripts may import it instead, and early-access calls will + fail. Uninstall the official package (or replace it with the one you generated) to avoid this. diff --git a/meraki/session/async_.py b/meraki/session/async_.py index 90829fca..652760be 100644 --- a/meraki/session/async_.py +++ b/meraki/session/async_.py @@ -176,7 +176,7 @@ async def request(self, metadata: Dict[str, Any], method: str, url: str, **kwarg # Prepare transport-specific kwargs kwargs = self._transport_kwargs(kwargs) - # aiohttp manipulates URLs as instances of yarl.URL + # Coerce non-str URLs (e.g. yarl.URL from legacy callers) to plain str if not isinstance(url, str): url = str(url) @@ -315,7 +315,7 @@ async def _handle_success_async( return None, None def _handle_redirect_async(self, response: Any) -> str: - """Handle 3xx redirects for aiohttp responses.""" + """Handle 3xx redirects for httpx responses.""" abs_url = str(response.headers["Location"]) substring = "meraki.com/api/v" if substring not in abs_url: From 49b2c0a8cba4f873f7b9b7ca63a7b82746c15e0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2026 15:50:05 +0000 Subject: [PATCH 03/11] chore(deps-dev): bump hypothesis in the all-deps group (#448) Bumps the all-deps group with 1 update: [hypothesis](https://github.com/HypothesisWorks/hypothesis). Updates `hypothesis` from 6.156.3 to 6.156.4 - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/v6.156.3...v6.156.4) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.156.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 95 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/uv.lock b/uv.lock index e33c5ea4..1f83d4ed 100644 --- a/uv.lock +++ b/uv.lock @@ -215,54 +215,61 @@ wheels = [ [[package]] name = "hypothesis" -version = "6.156.3" +version = "6.156.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/4b/d376c0382fc716878790177deb88cc8b73d3a0218ae74de6e14493f7dc74/hypothesis-6.156.3.tar.gz", hash = "sha256:0c68209d611a17d9092a74d4a7c945256b8c7288e4e2b8a8a3c3be716a284365", size = 476259, upload-time = "2026-07-08T11:27:23.758Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/f5/2838f39dcf725c766cee1c3f077f71c027279082ba8c91eab69c916d4e92/hypothesis-6.156.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:49b8a2ccad35987f536dab81cdee12ea53ab5e87fae079cfb2517f47bde11c59", size = 749193, upload-time = "2026-07-08T11:27:20.607Z" }, - { url = "https://files.pythonhosted.org/packages/e2/db/4a7661d29ea88d42e0e0544c8d0b54f56e4ccb391b1c0ad97421b3100889/hypothesis-6.156.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:91a48e40a4fab58f454b42fcab21306488637ae3a6fbf757f7d044e29306119d", size = 743707, upload-time = "2026-07-08T11:26:18.443Z" }, - { url = "https://files.pythonhosted.org/packages/4a/a9/ee98adf01d7d92b0cae5855eef1f9df7ae294154643cf29d64b4a1b65e83/hypothesis-6.156.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b23da0553cd12f448211d1e94274351978b0a1cfa62b603a97e289d8e3432b9a", size = 1070975, upload-time = "2026-07-08T11:26:29.681Z" }, - { url = "https://files.pythonhosted.org/packages/40/8f/cc6ddf1062e0ca3cb499582d25de6713521ef448d109526a81f27eb3eef7/hypothesis-6.156.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcc75a2bf4e250bcb67d74b2a423e149adf69b6730fd9de78d97494d7d4146d4", size = 1120657, upload-time = "2026-07-08T11:26:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/26/a0/e3478fea1242d4fcd1c5e20bf6fb8db80cfef27b4407995e7e9f7452148d/hypothesis-6.156.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d5a453ae95e471e70de86fc07eda86d096c47fa9059b83b26316b5c0e54e6fcd", size = 1245183, upload-time = "2026-07-08T11:27:17.085Z" }, - { url = "https://files.pythonhosted.org/packages/73/00/cb6fb0c2430960de30a3927432569aaba30db80b28c513abdabfd06fe8b0/hypothesis-6.156.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5fb3bbf324030a850adc17c26c09ef9856bf73f19e27dfb3b2a7c72f6ee05c9", size = 1287894, upload-time = "2026-07-08T11:27:10.517Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ff/abc3922baf5f03864b3b9fab334be0a05702060ad0ca90ffeafbc890bb4d/hypothesis-6.156.3-cp311-cp311-win_amd64.whl", hash = "sha256:56a84fa7172c3166f4ceaa44ecb72715ed2be59f5b1ae49a27fff2c4cb6cc251", size = 640180, upload-time = "2026-07-08T11:26:45.899Z" }, - { url = "https://files.pythonhosted.org/packages/52/37/8f1d7ed73656d56d94b8da1d0ee429bab70015e78c33933b1b41f41958a9/hypothesis-6.156.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f009db55dc3227ed1040dc69f446fa672a64d240408856a34419cd841cfc7b9b", size = 749042, upload-time = "2026-07-08T11:27:12.126Z" }, - { url = "https://files.pythonhosted.org/packages/90/db/5be0f96e830e376d38d1cb2b9a0d55ce0e714aa4992692be5311f820a157/hypothesis-6.156.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e58baa63416d4ad5b5722f683dd85205b00d6b1aed42914eda5f3f5c36ec5c4", size = 741867, upload-time = "2026-07-08T11:27:08.89Z" }, - { url = "https://files.pythonhosted.org/packages/3a/70/4e96a883f1f71cdb4c626ce8e818279be97ab4cafcae7ec288d79a48028f/hypothesis-6.156.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3974fdbacfb37ea6a7c503e3e355992f1ae19658ac920661492d03863ffa0c58", size = 1069806, upload-time = "2026-07-08T11:26:52.58Z" }, - { url = "https://files.pythonhosted.org/packages/69/a8/c1071a89cd981a0f9d22a5723a79253ec4ff68f60d196b6aaaaea38b5b74/hypothesis-6.156.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55948a48d348a448acd33b908cfb2c3e88a4560b3d5e6d38bfb2650ea389e69b", size = 1119589, upload-time = "2026-07-08T11:26:39.81Z" }, - { url = "https://files.pythonhosted.org/packages/b7/2c/27336f452eddeceaf173e7ea3b34383e6febe872958483253cb3e2989db2/hypothesis-6.156.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dfe4bce2bd2770f2d11ec2dee3469221939eb109ee28a91649fd7f27700ff263", size = 1243866, upload-time = "2026-07-08T11:26:12.252Z" }, - { url = "https://files.pythonhosted.org/packages/27/22/b9b67469777fe1359d694b92903bd2d516b58bf85915045461aae84fa093/hypothesis-6.156.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:592c67d32ee58026556ad26ddbf76a873f5b0c9d0a0104f73db9db0dfba32f18", size = 1286420, upload-time = "2026-07-08T11:26:19.802Z" }, - { url = "https://files.pythonhosted.org/packages/36/36/60f8451ac90b1550feb7f7f1a858742beb31746465dcc370cfb675d53b06/hypothesis-6.156.3-cp312-cp312-win_amd64.whl", hash = "sha256:d39c149673b9d86be6cb9df01d1a4e8081f26e8093eabc957d6769b8b3afa6d8", size = 637647, upload-time = "2026-07-08T11:27:15.438Z" }, - { url = "https://files.pythonhosted.org/packages/dd/b8/9d7dce42c9534bd9d3ddfa2bb95a8efa82fb0b9a7a89bc14fcd9fac10368/hypothesis-6.156.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:775d70e3cf5c0cd83239b62ab60d2ddbbddd026bba57aa6deeeaed6aa83f5002", size = 749455, upload-time = "2026-07-08T11:26:47.428Z" }, - { url = "https://files.pythonhosted.org/packages/02/81/6b2d101825302b8200e88b0d6e4b0e0ca93a8966097669614c33d61265b7/hypothesis-6.156.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f0f2acd5b9a462e0d2589b7600c563c39808a8683c2d614d1caaabeb1c67c062", size = 742058, upload-time = "2026-07-08T11:26:23.942Z" }, - { url = "https://files.pythonhosted.org/packages/4d/5a/342f103a6ec6fb77897f2030f00075d4d84d4afbfb7944cddca334cf5a98/hypothesis-6.156.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fbe0888b4ab8253ca44b763faa56d37a10d602480ecc2f03a09d96b3a1bf8", size = 1069965, upload-time = "2026-07-08T11:26:31.233Z" }, - { url = "https://files.pythonhosted.org/packages/84/cb/86a44d644c28251fc6f2799bc8c5d97358bf00f7417a18eb0783cc597d77/hypothesis-6.156.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70eb849033695e5b81f0241019751d7b60ecea248c993f5e1536a1bd0caa6d7", size = 1119954, upload-time = "2026-07-08T11:26:55.917Z" }, - { url = "https://files.pythonhosted.org/packages/68/99/ec84b29ec0f9bc646fb98655c76d4ced5e44309f26b86fc58b20c9d0634e/hypothesis-6.156.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0e2eb13d32f5dfeacd59979b9acf8e647d4d6f5b4b0a18b277db59b0ec7994eb", size = 1244030, upload-time = "2026-07-08T11:26:33.846Z" }, - { url = "https://files.pythonhosted.org/packages/54/15/74a7c54493763707325e67be90aba13e144b6296224fb1a1907d22bf1452/hypothesis-6.156.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64b606f915bb84b880b479c31fed1b283aab8b0d5c59e6ba2c314e9a35c686f4", size = 1286706, upload-time = "2026-07-08T11:26:51.02Z" }, - { url = "https://files.pythonhosted.org/packages/d6/41/275cbcacc49c22e5e717a7217a0b1accfaae6fefefce8af39b4fae5a13a2/hypothesis-6.156.3-cp313-cp313-win_amd64.whl", hash = "sha256:a68d2d46442e48f90844d939fb372d96f96972017b4314c7418d82f20c9f1aa3", size = 637935, upload-time = "2026-07-08T11:26:13.557Z" }, - { url = "https://files.pythonhosted.org/packages/52/d1/d106f75214f7abc28abfcc4ae5a87cc7b445dfe7dd738d1b86d079a61741/hypothesis-6.156.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d5883bd0e7e1a54a478553cc1c57dbd14b751562f5134abe4742ba1d7267a14b", size = 749486, upload-time = "2026-07-08T11:26:59.432Z" }, - { url = "https://files.pythonhosted.org/packages/ca/84/84d1cbe3b2812eba795b2137b579582f1189256d996d27ee42a974edb240/hypothesis-6.156.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5bc9b4258403ebdc01121c6cc9cb4a3967ca5a569a5168a80c34828b3d6ab264", size = 742264, upload-time = "2026-07-08T11:26:16.003Z" }, - { url = "https://files.pythonhosted.org/packages/94/28/ede93daa4fe869aa42abcaaba9da14024d61ed313ac6c8373634b1359185/hypothesis-6.156.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6d73e6f15ec5e412ab4aca148a2673033a1728072a4d33b600f8f5d84af819", size = 1070142, upload-time = "2026-07-08T11:27:22.149Z" }, - { url = "https://files.pythonhosted.org/packages/55/59/8f595b2f2a594ab7834a588bbcd11ed053cb054a5bad399015f4df6be3ae/hypothesis-6.156.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4f7029436f51e98e6a5d78cb1ecab1ef5a0f3517dbab003429b8a65e47f9a41", size = 1120144, upload-time = "2026-07-08T11:26:38.368Z" }, - { url = "https://files.pythonhosted.org/packages/ca/de/3bbdf04a66e09d730048d5e82722df6fd1047187c02c2764dd9d19423353/hypothesis-6.156.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:67d1d3053d077b0715a50d92decf578742aa2ab4cec713a56e722abd33361cca", size = 1244300, upload-time = "2026-07-08T11:26:14.746Z" }, - { url = "https://files.pythonhosted.org/packages/36/37/dd0fac3b7042a37a284f055461500018656a80bfcca246124f253772a99a/hypothesis-6.156.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:83389a53144ce61c6789cc0a43fefe26c257dcb8b23ccd9291db024b8ade3652", size = 1287218, upload-time = "2026-07-08T11:26:49.066Z" }, - { url = "https://files.pythonhosted.org/packages/3e/26/5310edd49abaa73a8fa41733fd9874781c9d4d94f03566231a2784de291e/hypothesis-6.156.3-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:0f3367fbaedc5527ef3ff717006f94db79a19473d7d0a5ecce0f0de926ed6143", size = 586422, upload-time = "2026-07-08T11:26:44.006Z" }, - { url = "https://files.pythonhosted.org/packages/ee/58/877f1c8aeaadced677f73f00ee00ffb22f0e93f052114d74c87cbb8742fd/hypothesis-6.156.3-cp314-cp314-win_amd64.whl", hash = "sha256:5ab613fde3d4324fae8c6f8cf217d5f463a82be0e9dee4f17d952230d0094612", size = 637731, upload-time = "2026-07-08T11:27:02.437Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c1/0d31764d9370f32cdaa1eb565fe617cbfb4e223efd0bff8433bcd2f4666e/hypothesis-6.156.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:93d45959fc889a63a66fff0923dfd25dda53ee181eebec81003ffbf5cd7c86f8", size = 747516, upload-time = "2026-07-08T11:26:17.282Z" }, - { url = "https://files.pythonhosted.org/packages/31/e5/a10345872f80688545c625a7c93f529aba2a0dfa8a6a5d18a0995c61aaf2/hypothesis-6.156.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0b58648a7f9705b98371ba6515da2f0415c440cb24fef34ee48857ae57740ef6", size = 740877, upload-time = "2026-07-08T11:26:41.19Z" }, - { url = "https://files.pythonhosted.org/packages/33/1d/434962713972eeb3f643ffd77b39f18a9f6867d8f07424447bb651bb8934/hypothesis-6.156.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95bd12f151cb79d55b7b9d3cd64c3fe7506c27d3fd54fac8cba2e7d847292da1", size = 1069163, upload-time = "2026-07-08T11:27:05.683Z" }, - { url = "https://files.pythonhosted.org/packages/96/d6/a9d52d6a830d0fc79af35ef46f678ed3f7fc0c8e186ec41c386aa9a1bff8/hypothesis-6.156.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67e53f029e7c31471e6de06bcb0c05f8f08630817c14c49e99d0d3e198082cf0", size = 1119238, upload-time = "2026-07-08T11:26:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/a7/f7/c228a4228304243845883f2feeda46c2f7dacbe0dc20ffae758bc6bbf5ef/hypothesis-6.156.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2470f9745bbe7fe98c5eeaa2f5e74ebdfed46d401efc7d82f0cd6ab3da8d9408", size = 1243071, upload-time = "2026-07-08T11:27:13.763Z" }, - { url = "https://files.pythonhosted.org/packages/4d/4c/b6ab46567e501b6b74cc98557c65afc55f6388e5ea4939ec9cd5e3da3b0b/hypothesis-6.156.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:05370d67210ce822eea53060ea723d1b70cde8c2bab5a5b10d557a9b81f51944", size = 1285531, upload-time = "2026-07-08T11:26:09.812Z" }, - { url = "https://files.pythonhosted.org/packages/a6/c5/939fb46bd62082379c34321fe315808a5f4afd4b1d78e3719e8bb36dda53/hypothesis-6.156.3-cp314-cp314t-win_amd64.whl", hash = "sha256:39cae9b690c49793bdce45daed45f9f37a38ab1360b74a328458ad56caac74f6", size = 637850, upload-time = "2026-07-08T11:26:54.49Z" }, - { url = "https://files.pythonhosted.org/packages/52/35/9c5d61a968ace9853a8121d20126fc9c8bbe09ca050a06a427a6254152a3/hypothesis-6.156.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e62c0782e6cead74c0c931bd78526ed9b8114a14b16ad631cbe5a59b33e5628a", size = 749744, upload-time = "2026-07-08T11:27:07.376Z" }, - { url = "https://files.pythonhosted.org/packages/70/51/937fcd17a9e56fc0f681f1ca822e3edeadcb2b984e86ff71218a6b26e647/hypothesis-6.156.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:06f8d858326bca887241145842da378423c4f6274e90fe2631a22fac107cc033", size = 744333, upload-time = "2026-07-08T11:26:26.963Z" }, - { url = "https://files.pythonhosted.org/packages/5f/c1/13ead61ebed8d0321fd8f5afb347e587cf738326e4feb8288803f799b467/hypothesis-6.156.3-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f815d099de262fbb11dee666534c7c808158aca5489808183253ffe5323657", size = 1071370, upload-time = "2026-07-08T11:26:25.363Z" }, - { url = "https://files.pythonhosted.org/packages/5c/e4/5f0a6d8fda7e818893fccd35eb08c930c52251a36a461dedb886da56b5aa/hypothesis-6.156.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc45ee9649f0803cdd3258b2ab59f7a083670d21105eb73967237911d86f6820", size = 1121413, upload-time = "2026-07-08T11:27:19.01Z" }, - { url = "https://files.pythonhosted.org/packages/34/c9/6249ed5dff9848c6b446b9e7cffc052b3c6882d05f7dda8c574874133218/hypothesis-6.156.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:838622aaebce6113111990014f9941bfb6d3481c135d93c4ae6dcc78a0d523c9", size = 640781, upload-time = "2026-07-08T11:27:04.058Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/00/52/22ec531bcc61d55b6858b15c176c9d3284d6447c8618f17e90ca174e8bcf/hypothesis-6.156.4.tar.gz", hash = "sha256:38deb10b31ba18dfdbf9f6803711720148cea5e493a298dfb187c2fe72456791", size = 476287, upload-time = "2026-07-08T21:55:29.786Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/b2/6ab1506f7540c689916af0ab89c15413656001c991b0da6256b51e54706e/hypothesis-6.156.4-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ba523e6ab93ee51f933ebab5bb62dadfd20762922b93e9f48b31655f1343fbd2", size = 748213, upload-time = "2026-07-08T21:54:01.971Z" }, + { url = "https://files.pythonhosted.org/packages/da/d6/d8c44fa442c767d8f2d582da8f5e9efb6719416a1276ed1b61cc70cc7bb8/hypothesis-6.156.4-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:eb225cfab4553913f3bbd535c688ffa684c70432810a0b50555bd8cf70dbdd09", size = 743036, upload-time = "2026-07-08T21:54:55.678Z" }, + { url = "https://files.pythonhosted.org/packages/b7/68/e99a04ec397f8e9d921249c9fb95c40f3842e889e9de4cbfc5ce77ebee03/hypothesis-6.156.4-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb061eefe1c25a2b3432b2d801f4931510bddc4a6f10c6b23f0c0d8215262bf7", size = 1070425, upload-time = "2026-07-08T21:55:19.511Z" }, + { url = "https://files.pythonhosted.org/packages/bf/12/f36f487d2adc08bc0f3159a9083857f1dcfc7f44e76142e56d0f35427202/hypothesis-6.156.4-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3250aa89a3cfacdf601c86d8eafa4a47161e05062afe851a2650d5c6c5fc8a4d", size = 1120438, upload-time = "2026-07-08T21:55:27.882Z" }, + { url = "https://files.pythonhosted.org/packages/58/d4/e93daa5124d90a43fd2b9ebcbcdd84995b91368c859e4eff4bbf0555bccf/hypothesis-6.156.4-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:60ceff7f4a058eeec032e7ad4e18aeff58860cd5819a88db78b0a49ccce25cc4", size = 1244772, upload-time = "2026-07-08T21:55:03.568Z" }, + { url = "https://files.pythonhosted.org/packages/4f/48/c77d590fef2888e18abce5de6ba2b022981deb97d175a4e1dffbe35997d1/hypothesis-6.156.4-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7ebada1b9ec964600a68e05a289abd8ee12edde02abc92653783f03346abfa5e", size = 1287496, upload-time = "2026-07-08T21:53:57.7Z" }, + { url = "https://files.pythonhosted.org/packages/83/18/861ea8097074f99a532439bce6873abfec66d11c4eb727fb2277189afa40/hypothesis-6.156.4-cp310-abi3-win_amd64.whl", hash = "sha256:d0d82e00b61a3866d97cbb43dce54532e352f93bf7f0600b3f1d00a7f24a88f5", size = 640374, upload-time = "2026-07-08T21:54:06.509Z" }, + { url = "https://files.pythonhosted.org/packages/85/a0/138ac58f597537e531be90cdcc4ef830514bb8fab2756c236c8d37c76730/hypothesis-6.156.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c6f5e041118701df743c561e22008d1eeecb5305e03291d8a3d3468946a9be5d", size = 749182, upload-time = "2026-07-08T21:53:52.13Z" }, + { url = "https://files.pythonhosted.org/packages/a0/33/3fb125a988d35464fccc120be644a74e8dcc80e2b532a9413f257c68cc03/hypothesis-6.156.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce644bf50fc3fec1ca4b993618ece303c7036a3cd833b26b33392a3134dd7070", size = 743700, upload-time = "2026-07-08T21:54:36.016Z" }, + { url = "https://files.pythonhosted.org/packages/88/08/1ed0e5ec6a8126468345fe4419e6d502025358184bc9428e7f3d772e3b7e/hypothesis-6.156.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77687165ad9fe324112ff098e598b5483c467840f2594feae47ce0e71ba12ff6", size = 1070978, upload-time = "2026-07-08T21:55:05.304Z" }, + { url = "https://files.pythonhosted.org/packages/24/1a/a45b4288ba88bfa3df02501fe06db505ee7a0e17cc724907be2b6af96996/hypothesis-6.156.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f3ac237d1377e201398d5c81aed0dfca85ecb47538f5df477b27f968123d917", size = 1120668, upload-time = "2026-07-08T21:55:21.627Z" }, + { url = "https://files.pythonhosted.org/packages/84/50/20265f6419a802ff26c7b6fdb3f1e655d18330695ffb68d7ded976eb65a0/hypothesis-6.156.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c3dd6e9847b738c12d1b9878f7eb6cba5970aec5e30de148aa510c6bdab3d617", size = 1245253, upload-time = "2026-07-08T21:54:29.599Z" }, + { url = "https://files.pythonhosted.org/packages/8b/57/7cdb87a3d83fbdd1ec38b8fe0c333ba731906b56480544b899af9c2c0e3b/hypothesis-6.156.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aaa4aa4045e0f7e542af06812feb241af71107b77f73a7e7599d6f70af358f18", size = 1287885, upload-time = "2026-07-08T21:54:34.48Z" }, + { url = "https://files.pythonhosted.org/packages/e8/b4/a1a6d21b89ce5b5a79b72a9898c61f33816072f0309c6da332bd9a5ebf31/hypothesis-6.156.4-cp311-cp311-win_amd64.whl", hash = "sha256:5b9a53b9c40dff7e6b97d4b0535576c8662dcf42315abc75deb5d190269c574e", size = 640181, upload-time = "2026-07-08T21:54:04.932Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/2f56c1aaa07586897feaac36a07ef68bedca4a410b796e5e0f77ecee0003/hypothesis-6.156.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f6958df0438cf9115fb880afaa9f02fb1ebcbefc763c4c374737ad4ca3f11cae", size = 749016, upload-time = "2026-07-08T21:54:23.132Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d1/d6b77e95a2cf5b572805491c53cb2c45eec0e7dff65c2310457d6537ad0f/hypothesis-6.156.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad091a3110fd5c4731251068c049a48fb33a9ef01f5901b88a81c68ab70c943b", size = 741911, upload-time = "2026-07-08T21:55:25.836Z" }, + { url = "https://files.pythonhosted.org/packages/e7/d3/229fdb1dac8dc1c103f95f3d128df3c63c07630778178cf42fbb2dd7376b/hypothesis-6.156.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15de4176d0365c9855898f75cf2986be6f361643c08f0d1bc154a89779a9cb89", size = 1069810, upload-time = "2026-07-08T21:54:57.762Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e1/03be6105682766e090cc6355f09fd461dfb473d952f8f07c2dff3d0fd74e/hypothesis-6.156.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19b70642500369f70743321e03359d2504e5f4d62cfd0046054867f79965d8bb", size = 1119552, upload-time = "2026-07-08T21:54:28.114Z" }, + { url = "https://files.pythonhosted.org/packages/88/3e/80ad5a0db03e7f07b07c8b1064cdf169695f09f68a3c62b03ae68e687c79/hypothesis-6.156.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7b7232c9ea9f947b6b5b1c317ac9ce988af2fbb076fa5a4836ff8e1d20f1b176", size = 1243862, upload-time = "2026-07-08T21:54:52.276Z" }, + { url = "https://files.pythonhosted.org/packages/7e/4c/af9661cabb126b8432c43996c925f8c4d174745d61616c8f00e7b6cc08ea/hypothesis-6.156.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bedc54bb398eaf54b9e1d88744c89b559fc8bf165c3e603f821cc53754ade241", size = 1286422, upload-time = "2026-07-08T21:54:39.323Z" }, + { url = "https://files.pythonhosted.org/packages/40/a8/c9c8e506122cb6cfc634b07ab0d7e8db7d5d51e27d9b937e20d61e1a272e/hypothesis-6.156.4-cp312-cp312-win_amd64.whl", hash = "sha256:b4217076cb7169fc17c32b06206c4503ad71d740eed0b3c20023a11f04418179", size = 637645, upload-time = "2026-07-08T21:54:26.268Z" }, + { url = "https://files.pythonhosted.org/packages/ae/4a/a4e797af1ba0cf8cddba7e460294bd25a2d6efc33db898efb288edc993a1/hypothesis-6.156.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2c799aee207d5ecf5af2fbf86250806245618e58cdb41c4606718a9ed001c706", size = 749445, upload-time = "2026-07-08T21:55:01.697Z" }, + { url = "https://files.pythonhosted.org/packages/62/02/6c66c992b02aee085b644d0400a75e086ce17c47ff83d7a2e1f48d657d57/hypothesis-6.156.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7af68750ed3ebcf32540e32fe111850fc40e9ba15be2613ef7f04620c51669c", size = 742079, upload-time = "2026-07-08T21:54:43.87Z" }, + { url = "https://files.pythonhosted.org/packages/79/04/be90e612f4b6e75752f0420d3945893ed0f71a04485867a7ad9c376f161e/hypothesis-6.156.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32e4c6988898e9e21c97f48b941cf1e10a5ea4f31db82e5722c1bf777d17c3dc", size = 1069972, upload-time = "2026-07-08T21:55:13.584Z" }, + { url = "https://files.pythonhosted.org/packages/2b/71/6e74917b591c56402f726f4c08bd819d586ea20857a029549541c3808330/hypothesis-6.156.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07f7207655919eedda6d888ca6cfcf83eeedff3fc34fc6a83aabe197fed4966b", size = 1119967, upload-time = "2026-07-08T21:54:14.468Z" }, + { url = "https://files.pythonhosted.org/packages/0b/e7/4619e6acdd4eca4b58dd69b036c61a60714741197be4ca7d3eda6ef616e4/hypothesis-6.156.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1db6caf5718eb90dad5d86254961bf2eda319542e9e0479c562327f649c2115b", size = 1244027, upload-time = "2026-07-08T21:54:42.371Z" }, + { url = "https://files.pythonhosted.org/packages/30/76/3e7b788502e0c9a5ef6830e63e63ae2b3001f213e6ea5313fde75d4bdadb/hypothesis-6.156.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5afdcd0f320dc4b443c51722860a893dcf03a12e5cd17e68143b28461a1c9da2", size = 1286704, upload-time = "2026-07-08T21:55:23.543Z" }, + { url = "https://files.pythonhosted.org/packages/72/97/46893ce86e106e00bd8224dc85bd6439c1bd24cf513f73e4719926bd8053/hypothesis-6.156.4-cp313-cp313-win_amd64.whl", hash = "sha256:32f63111e79020e530913673c2ef91642fc297ae552364acde00f70d50142b9a", size = 637938, upload-time = "2026-07-08T21:54:03.307Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ea/f2c4313475f54b55eb160e09fe139b520c1ea77ece9e05a24c8094261e89/hypothesis-6.156.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:a946f12823c004bc02d7cbdc9c2eb1943cb9c7f05c95f014e353d53e9c50ab14", size = 749476, upload-time = "2026-07-08T21:54:40.827Z" }, + { url = "https://files.pythonhosted.org/packages/66/8b/c364bd4a3504e9c7d895552aa69e4453fa3c2dfa63a4fdf37f97f539b457/hypothesis-6.156.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bedff9adcf0ad5fd8ce4d6ea5dda29ae316b0856beef4236460020a55ed30020", size = 742306, upload-time = "2026-07-08T21:54:21.53Z" }, + { url = "https://files.pythonhosted.org/packages/6f/53/1e05b2ffed333628656b5e1cee65f5a8dcca259c5be9221c0817dad74f14/hypothesis-6.156.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19aaa6c1f6a1d11b40e97ac62a58b5f2e4481e8c8b1ef132b582dd61dcc0e5b4", size = 1070146, upload-time = "2026-07-08T21:54:47.133Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/25c4fd4641497c4f2680ba8d8300c7e8d9c5c8bafea219f597580e587508/hypothesis-6.156.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d058917bdc3c7e575461ba81128d018819061a0291961cf4c90c0c8ed8c21436", size = 1120131, upload-time = "2026-07-08T21:53:55.874Z" }, + { url = "https://files.pythonhosted.org/packages/1b/18/d59e50d48bfb6697980fc0ff02e3fc1e32a71a4d549a1939be7d90d4b057/hypothesis-6.156.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bbb5ea5be2f9ee115332a896eb45ab4018aee13a702a4562a29947d7206ef65d", size = 1244302, upload-time = "2026-07-08T21:55:15.549Z" }, + { url = "https://files.pythonhosted.org/packages/8a/c2/60666d23338fb4e33ff28e87f0579dd16cd99cfe5972448b1b79ec1b96e3/hypothesis-6.156.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ce314d1dff756be7b0173ab8c72697bbe4c831ed765b8ef6b1aeb0a7056da42", size = 1287215, upload-time = "2026-07-08T21:54:17.549Z" }, + { url = "https://files.pythonhosted.org/packages/4a/39/24410320c5bddf58d72e3c61da91b56f889279d52dc38a3695662f22255b/hypothesis-6.156.4-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:139b9306e84b8c25c0aef9eec67e096f92fa6557a6088e56e58bdcbd7974f0c4", size = 586424, upload-time = "2026-07-08T21:54:45.356Z" }, + { url = "https://files.pythonhosted.org/packages/83/9a/e1cf9393b3686ceb23b87d8f7f4c5c3e1f4751b974642439e99b70bb0272/hypothesis-6.156.4-cp314-cp314-win_amd64.whl", hash = "sha256:e65d36b2cfb863a15ab3fd81d5de741df9b51f2b56c5f7ecee637b8e9333938d", size = 637751, upload-time = "2026-07-08T21:54:24.576Z" }, + { url = "https://files.pythonhosted.org/packages/95/3f/25fa799861ed2c1e32c9064d02ad3090e0f282f2a1efed98d744a4be6970/hypothesis-6.156.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:454b2ea256feda13edd8c9514f2898a949e4f96b0156c67a852cbfe1f777055a", size = 747509, upload-time = "2026-07-08T21:54:11.308Z" }, + { url = "https://files.pythonhosted.org/packages/a0/ac/a2ec42a5fc0789c6a953c98ee299afd0c6fe80a16c0836e3285697614d0e/hypothesis-6.156.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8db65e17fb1e6dcaf34d4ad69a104d1437409e58178fc752b6344394d0a35f71", size = 740865, upload-time = "2026-07-08T21:54:19.761Z" }, + { url = "https://files.pythonhosted.org/packages/ae/df/e87653a9a1de9fb838237b7f6b22a76cfa52cb21ba4b98622f2b25c00bac/hypothesis-6.156.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44af150302f88aec7f0b90566c0f27edb847f0d23cbe729fe75cfe582089366e", size = 1069164, upload-time = "2026-07-08T21:54:08.121Z" }, + { url = "https://files.pythonhosted.org/packages/58/fc/bf1d6d4e783d163434ec3a5a692588f8deee772538de6cb9cd52417c543e/hypothesis-6.156.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f7707302553bddf84826a44821055b2ddf460c9199a92bd60f0da8b39b42872", size = 1119203, upload-time = "2026-07-08T21:53:54.321Z" }, + { url = "https://files.pythonhosted.org/packages/be/f3/b7802b9db8fa6d2caefb143e9a8fe47145ba9ce74e276eb6abd2fd0b0b8c/hypothesis-6.156.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:618e7edf24c9b1d932f0ba835ee5f8571a197143bbaf5467a5c8f180f96494ee", size = 1243073, upload-time = "2026-07-08T21:55:11.703Z" }, + { url = "https://files.pythonhosted.org/packages/1a/90/70c5605c35c72dddf2be50e88d017e9139ae68e1ac7aaf29dc90732fa8e5/hypothesis-6.156.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ff172915bafafc827981f3bab3bd076ad96e05d108c43a19373ccf3be085c727", size = 1285526, upload-time = "2026-07-08T21:55:07.271Z" }, + { url = "https://files.pythonhosted.org/packages/a6/43/a4f1b41e410d8bfe78f17eeaac08cee4e326b341345009802e073d20af71/hypothesis-6.156.4-cp314-cp314t-win_amd64.whl", hash = "sha256:0725c7e2c3bd863e75aae8d5be1f650abc9a3774200055461e1142625af9419c", size = 637843, upload-time = "2026-07-08T21:54:12.858Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ac/c5495b2c4070f80665660cfbc8ee81a1bc3e254565f41d66ecd5c3a4724c/hypothesis-6.156.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6f3bef67bd9ddce33ee9017f05a3670eac2518f27f80a9ab3112ac4d7772f293", size = 749728, upload-time = "2026-07-08T21:54:31.273Z" }, + { url = "https://files.pythonhosted.org/packages/3c/58/f46decb99415e08d80d915235899cc7e8ba02ee7f9effebc93fcdcd5315b/hypothesis-6.156.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0ca6a4785c058257a729daa218d9c9d06d05db42da4f52484c590f57f7905d5b", size = 744371, upload-time = "2026-07-08T21:54:50.653Z" }, + { url = "https://files.pythonhosted.org/packages/44/ec/c8c19542f6389580e6281f87802849754b8910d29e0a7e36e32ac4e18811/hypothesis-6.156.4-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7338ee15ee84ef994ae3d1a2e71d25c82713bf5ec27f55442755ae15e38369b", size = 1071376, upload-time = "2026-07-08T21:54:54.003Z" }, + { url = "https://files.pythonhosted.org/packages/b5/10/57cc273baf0cfe722eaa903c72db7ca45e7df4cc0780f80cb5dfe50edbbf/hypothesis-6.156.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:539be6819696560c23ff6c0d0af4e7c1ea4936123f4433b511977a79adc371d5", size = 1121429, upload-time = "2026-07-08T21:55:17.323Z" }, + { url = "https://files.pythonhosted.org/packages/68/cf/4b31c31716980972f7b5dfd75fe11021e9b8b6dd09664cc5a82c8c03c2bc/hypothesis-6.156.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b1717bc41d1a0683470f950c565ade33a52c28f600b1aa824d74f651a36e2c7b", size = 640761, upload-time = "2026-07-08T21:54:37.716Z" }, ] [[package]] From aa1debfb58f3706e87968363d42718663dbd9319 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:38:40 +0000 Subject: [PATCH 04/11] chore(deps-dev): bump the all-deps group with 2 updates (#450) Bumps the all-deps group with 2 updates: [ruff](https://github.com/astral-sh/ruff) and [hypothesis](https://github.com/HypothesisWorks/hypothesis). Updates `ruff` from 0.15.20 to 0.15.21 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.20...0.15.21) Updates `hypothesis` from 6.156.4 to 6.156.5 - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/v6.156.4...v6.156.5) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.21 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all-deps - dependency-name: hypothesis dependency-version: 6.156.5 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 146 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 74 insertions(+), 72 deletions(-) diff --git a/uv.lock b/uv.lock index 1f83d4ed..715dff68 100644 --- a/uv.lock +++ b/uv.lock @@ -215,61 +215,63 @@ wheels = [ [[package]] name = "hypothesis" -version = "6.156.4" +version = "6.156.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/52/22ec531bcc61d55b6858b15c176c9d3284d6447c8618f17e90ca174e8bcf/hypothesis-6.156.4.tar.gz", hash = "sha256:38deb10b31ba18dfdbf9f6803711720148cea5e493a298dfb187c2fe72456791", size = 476287, upload-time = "2026-07-08T21:55:29.786Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/b2/6ab1506f7540c689916af0ab89c15413656001c991b0da6256b51e54706e/hypothesis-6.156.4-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ba523e6ab93ee51f933ebab5bb62dadfd20762922b93e9f48b31655f1343fbd2", size = 748213, upload-time = "2026-07-08T21:54:01.971Z" }, - { url = "https://files.pythonhosted.org/packages/da/d6/d8c44fa442c767d8f2d582da8f5e9efb6719416a1276ed1b61cc70cc7bb8/hypothesis-6.156.4-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:eb225cfab4553913f3bbd535c688ffa684c70432810a0b50555bd8cf70dbdd09", size = 743036, upload-time = "2026-07-08T21:54:55.678Z" }, - { url = "https://files.pythonhosted.org/packages/b7/68/e99a04ec397f8e9d921249c9fb95c40f3842e889e9de4cbfc5ce77ebee03/hypothesis-6.156.4-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb061eefe1c25a2b3432b2d801f4931510bddc4a6f10c6b23f0c0d8215262bf7", size = 1070425, upload-time = "2026-07-08T21:55:19.511Z" }, - { url = "https://files.pythonhosted.org/packages/bf/12/f36f487d2adc08bc0f3159a9083857f1dcfc7f44e76142e56d0f35427202/hypothesis-6.156.4-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3250aa89a3cfacdf601c86d8eafa4a47161e05062afe851a2650d5c6c5fc8a4d", size = 1120438, upload-time = "2026-07-08T21:55:27.882Z" }, - { url = "https://files.pythonhosted.org/packages/58/d4/e93daa5124d90a43fd2b9ebcbcdd84995b91368c859e4eff4bbf0555bccf/hypothesis-6.156.4-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:60ceff7f4a058eeec032e7ad4e18aeff58860cd5819a88db78b0a49ccce25cc4", size = 1244772, upload-time = "2026-07-08T21:55:03.568Z" }, - { url = "https://files.pythonhosted.org/packages/4f/48/c77d590fef2888e18abce5de6ba2b022981deb97d175a4e1dffbe35997d1/hypothesis-6.156.4-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7ebada1b9ec964600a68e05a289abd8ee12edde02abc92653783f03346abfa5e", size = 1287496, upload-time = "2026-07-08T21:53:57.7Z" }, - { url = "https://files.pythonhosted.org/packages/83/18/861ea8097074f99a532439bce6873abfec66d11c4eb727fb2277189afa40/hypothesis-6.156.4-cp310-abi3-win_amd64.whl", hash = "sha256:d0d82e00b61a3866d97cbb43dce54532e352f93bf7f0600b3f1d00a7f24a88f5", size = 640374, upload-time = "2026-07-08T21:54:06.509Z" }, - { url = "https://files.pythonhosted.org/packages/85/a0/138ac58f597537e531be90cdcc4ef830514bb8fab2756c236c8d37c76730/hypothesis-6.156.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c6f5e041118701df743c561e22008d1eeecb5305e03291d8a3d3468946a9be5d", size = 749182, upload-time = "2026-07-08T21:53:52.13Z" }, - { url = "https://files.pythonhosted.org/packages/a0/33/3fb125a988d35464fccc120be644a74e8dcc80e2b532a9413f257c68cc03/hypothesis-6.156.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce644bf50fc3fec1ca4b993618ece303c7036a3cd833b26b33392a3134dd7070", size = 743700, upload-time = "2026-07-08T21:54:36.016Z" }, - { url = "https://files.pythonhosted.org/packages/88/08/1ed0e5ec6a8126468345fe4419e6d502025358184bc9428e7f3d772e3b7e/hypothesis-6.156.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77687165ad9fe324112ff098e598b5483c467840f2594feae47ce0e71ba12ff6", size = 1070978, upload-time = "2026-07-08T21:55:05.304Z" }, - { url = "https://files.pythonhosted.org/packages/24/1a/a45b4288ba88bfa3df02501fe06db505ee7a0e17cc724907be2b6af96996/hypothesis-6.156.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f3ac237d1377e201398d5c81aed0dfca85ecb47538f5df477b27f968123d917", size = 1120668, upload-time = "2026-07-08T21:55:21.627Z" }, - { url = "https://files.pythonhosted.org/packages/84/50/20265f6419a802ff26c7b6fdb3f1e655d18330695ffb68d7ded976eb65a0/hypothesis-6.156.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c3dd6e9847b738c12d1b9878f7eb6cba5970aec5e30de148aa510c6bdab3d617", size = 1245253, upload-time = "2026-07-08T21:54:29.599Z" }, - { url = "https://files.pythonhosted.org/packages/8b/57/7cdb87a3d83fbdd1ec38b8fe0c333ba731906b56480544b899af9c2c0e3b/hypothesis-6.156.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aaa4aa4045e0f7e542af06812feb241af71107b77f73a7e7599d6f70af358f18", size = 1287885, upload-time = "2026-07-08T21:54:34.48Z" }, - { url = "https://files.pythonhosted.org/packages/e8/b4/a1a6d21b89ce5b5a79b72a9898c61f33816072f0309c6da332bd9a5ebf31/hypothesis-6.156.4-cp311-cp311-win_amd64.whl", hash = "sha256:5b9a53b9c40dff7e6b97d4b0535576c8662dcf42315abc75deb5d190269c574e", size = 640181, upload-time = "2026-07-08T21:54:04.932Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/2f56c1aaa07586897feaac36a07ef68bedca4a410b796e5e0f77ecee0003/hypothesis-6.156.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f6958df0438cf9115fb880afaa9f02fb1ebcbefc763c4c374737ad4ca3f11cae", size = 749016, upload-time = "2026-07-08T21:54:23.132Z" }, - { url = "https://files.pythonhosted.org/packages/2d/d1/d6b77e95a2cf5b572805491c53cb2c45eec0e7dff65c2310457d6537ad0f/hypothesis-6.156.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad091a3110fd5c4731251068c049a48fb33a9ef01f5901b88a81c68ab70c943b", size = 741911, upload-time = "2026-07-08T21:55:25.836Z" }, - { url = "https://files.pythonhosted.org/packages/e7/d3/229fdb1dac8dc1c103f95f3d128df3c63c07630778178cf42fbb2dd7376b/hypothesis-6.156.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15de4176d0365c9855898f75cf2986be6f361643c08f0d1bc154a89779a9cb89", size = 1069810, upload-time = "2026-07-08T21:54:57.762Z" }, - { url = "https://files.pythonhosted.org/packages/fa/e1/03be6105682766e090cc6355f09fd461dfb473d952f8f07c2dff3d0fd74e/hypothesis-6.156.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19b70642500369f70743321e03359d2504e5f4d62cfd0046054867f79965d8bb", size = 1119552, upload-time = "2026-07-08T21:54:28.114Z" }, - { url = "https://files.pythonhosted.org/packages/88/3e/80ad5a0db03e7f07b07c8b1064cdf169695f09f68a3c62b03ae68e687c79/hypothesis-6.156.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7b7232c9ea9f947b6b5b1c317ac9ce988af2fbb076fa5a4836ff8e1d20f1b176", size = 1243862, upload-time = "2026-07-08T21:54:52.276Z" }, - { url = "https://files.pythonhosted.org/packages/7e/4c/af9661cabb126b8432c43996c925f8c4d174745d61616c8f00e7b6cc08ea/hypothesis-6.156.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bedc54bb398eaf54b9e1d88744c89b559fc8bf165c3e603f821cc53754ade241", size = 1286422, upload-time = "2026-07-08T21:54:39.323Z" }, - { url = "https://files.pythonhosted.org/packages/40/a8/c9c8e506122cb6cfc634b07ab0d7e8db7d5d51e27d9b937e20d61e1a272e/hypothesis-6.156.4-cp312-cp312-win_amd64.whl", hash = "sha256:b4217076cb7169fc17c32b06206c4503ad71d740eed0b3c20023a11f04418179", size = 637645, upload-time = "2026-07-08T21:54:26.268Z" }, - { url = "https://files.pythonhosted.org/packages/ae/4a/a4e797af1ba0cf8cddba7e460294bd25a2d6efc33db898efb288edc993a1/hypothesis-6.156.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2c799aee207d5ecf5af2fbf86250806245618e58cdb41c4606718a9ed001c706", size = 749445, upload-time = "2026-07-08T21:55:01.697Z" }, - { url = "https://files.pythonhosted.org/packages/62/02/6c66c992b02aee085b644d0400a75e086ce17c47ff83d7a2e1f48d657d57/hypothesis-6.156.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7af68750ed3ebcf32540e32fe111850fc40e9ba15be2613ef7f04620c51669c", size = 742079, upload-time = "2026-07-08T21:54:43.87Z" }, - { url = "https://files.pythonhosted.org/packages/79/04/be90e612f4b6e75752f0420d3945893ed0f71a04485867a7ad9c376f161e/hypothesis-6.156.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32e4c6988898e9e21c97f48b941cf1e10a5ea4f31db82e5722c1bf777d17c3dc", size = 1069972, upload-time = "2026-07-08T21:55:13.584Z" }, - { url = "https://files.pythonhosted.org/packages/2b/71/6e74917b591c56402f726f4c08bd819d586ea20857a029549541c3808330/hypothesis-6.156.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07f7207655919eedda6d888ca6cfcf83eeedff3fc34fc6a83aabe197fed4966b", size = 1119967, upload-time = "2026-07-08T21:54:14.468Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e7/4619e6acdd4eca4b58dd69b036c61a60714741197be4ca7d3eda6ef616e4/hypothesis-6.156.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1db6caf5718eb90dad5d86254961bf2eda319542e9e0479c562327f649c2115b", size = 1244027, upload-time = "2026-07-08T21:54:42.371Z" }, - { url = "https://files.pythonhosted.org/packages/30/76/3e7b788502e0c9a5ef6830e63e63ae2b3001f213e6ea5313fde75d4bdadb/hypothesis-6.156.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5afdcd0f320dc4b443c51722860a893dcf03a12e5cd17e68143b28461a1c9da2", size = 1286704, upload-time = "2026-07-08T21:55:23.543Z" }, - { url = "https://files.pythonhosted.org/packages/72/97/46893ce86e106e00bd8224dc85bd6439c1bd24cf513f73e4719926bd8053/hypothesis-6.156.4-cp313-cp313-win_amd64.whl", hash = "sha256:32f63111e79020e530913673c2ef91642fc297ae552364acde00f70d50142b9a", size = 637938, upload-time = "2026-07-08T21:54:03.307Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ea/f2c4313475f54b55eb160e09fe139b520c1ea77ece9e05a24c8094261e89/hypothesis-6.156.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:a946f12823c004bc02d7cbdc9c2eb1943cb9c7f05c95f014e353d53e9c50ab14", size = 749476, upload-time = "2026-07-08T21:54:40.827Z" }, - { url = "https://files.pythonhosted.org/packages/66/8b/c364bd4a3504e9c7d895552aa69e4453fa3c2dfa63a4fdf37f97f539b457/hypothesis-6.156.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bedff9adcf0ad5fd8ce4d6ea5dda29ae316b0856beef4236460020a55ed30020", size = 742306, upload-time = "2026-07-08T21:54:21.53Z" }, - { url = "https://files.pythonhosted.org/packages/6f/53/1e05b2ffed333628656b5e1cee65f5a8dcca259c5be9221c0817dad74f14/hypothesis-6.156.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19aaa6c1f6a1d11b40e97ac62a58b5f2e4481e8c8b1ef132b582dd61dcc0e5b4", size = 1070146, upload-time = "2026-07-08T21:54:47.133Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/25c4fd4641497c4f2680ba8d8300c7e8d9c5c8bafea219f597580e587508/hypothesis-6.156.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d058917bdc3c7e575461ba81128d018819061a0291961cf4c90c0c8ed8c21436", size = 1120131, upload-time = "2026-07-08T21:53:55.874Z" }, - { url = "https://files.pythonhosted.org/packages/1b/18/d59e50d48bfb6697980fc0ff02e3fc1e32a71a4d549a1939be7d90d4b057/hypothesis-6.156.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bbb5ea5be2f9ee115332a896eb45ab4018aee13a702a4562a29947d7206ef65d", size = 1244302, upload-time = "2026-07-08T21:55:15.549Z" }, - { url = "https://files.pythonhosted.org/packages/8a/c2/60666d23338fb4e33ff28e87f0579dd16cd99cfe5972448b1b79ec1b96e3/hypothesis-6.156.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ce314d1dff756be7b0173ab8c72697bbe4c831ed765b8ef6b1aeb0a7056da42", size = 1287215, upload-time = "2026-07-08T21:54:17.549Z" }, - { url = "https://files.pythonhosted.org/packages/4a/39/24410320c5bddf58d72e3c61da91b56f889279d52dc38a3695662f22255b/hypothesis-6.156.4-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:139b9306e84b8c25c0aef9eec67e096f92fa6557a6088e56e58bdcbd7974f0c4", size = 586424, upload-time = "2026-07-08T21:54:45.356Z" }, - { url = "https://files.pythonhosted.org/packages/83/9a/e1cf9393b3686ceb23b87d8f7f4c5c3e1f4751b974642439e99b70bb0272/hypothesis-6.156.4-cp314-cp314-win_amd64.whl", hash = "sha256:e65d36b2cfb863a15ab3fd81d5de741df9b51f2b56c5f7ecee637b8e9333938d", size = 637751, upload-time = "2026-07-08T21:54:24.576Z" }, - { url = "https://files.pythonhosted.org/packages/95/3f/25fa799861ed2c1e32c9064d02ad3090e0f282f2a1efed98d744a4be6970/hypothesis-6.156.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:454b2ea256feda13edd8c9514f2898a949e4f96b0156c67a852cbfe1f777055a", size = 747509, upload-time = "2026-07-08T21:54:11.308Z" }, - { url = "https://files.pythonhosted.org/packages/a0/ac/a2ec42a5fc0789c6a953c98ee299afd0c6fe80a16c0836e3285697614d0e/hypothesis-6.156.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8db65e17fb1e6dcaf34d4ad69a104d1437409e58178fc752b6344394d0a35f71", size = 740865, upload-time = "2026-07-08T21:54:19.761Z" }, - { url = "https://files.pythonhosted.org/packages/ae/df/e87653a9a1de9fb838237b7f6b22a76cfa52cb21ba4b98622f2b25c00bac/hypothesis-6.156.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44af150302f88aec7f0b90566c0f27edb847f0d23cbe729fe75cfe582089366e", size = 1069164, upload-time = "2026-07-08T21:54:08.121Z" }, - { url = "https://files.pythonhosted.org/packages/58/fc/bf1d6d4e783d163434ec3a5a692588f8deee772538de6cb9cd52417c543e/hypothesis-6.156.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f7707302553bddf84826a44821055b2ddf460c9199a92bd60f0da8b39b42872", size = 1119203, upload-time = "2026-07-08T21:53:54.321Z" }, - { url = "https://files.pythonhosted.org/packages/be/f3/b7802b9db8fa6d2caefb143e9a8fe47145ba9ce74e276eb6abd2fd0b0b8c/hypothesis-6.156.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:618e7edf24c9b1d932f0ba835ee5f8571a197143bbaf5467a5c8f180f96494ee", size = 1243073, upload-time = "2026-07-08T21:55:11.703Z" }, - { url = "https://files.pythonhosted.org/packages/1a/90/70c5605c35c72dddf2be50e88d017e9139ae68e1ac7aaf29dc90732fa8e5/hypothesis-6.156.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ff172915bafafc827981f3bab3bd076ad96e05d108c43a19373ccf3be085c727", size = 1285526, upload-time = "2026-07-08T21:55:07.271Z" }, - { url = "https://files.pythonhosted.org/packages/a6/43/a4f1b41e410d8bfe78f17eeaac08cee4e326b341345009802e073d20af71/hypothesis-6.156.4-cp314-cp314t-win_amd64.whl", hash = "sha256:0725c7e2c3bd863e75aae8d5be1f650abc9a3774200055461e1142625af9419c", size = 637843, upload-time = "2026-07-08T21:54:12.858Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ac/c5495b2c4070f80665660cfbc8ee81a1bc3e254565f41d66ecd5c3a4724c/hypothesis-6.156.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6f3bef67bd9ddce33ee9017f05a3670eac2518f27f80a9ab3112ac4d7772f293", size = 749728, upload-time = "2026-07-08T21:54:31.273Z" }, - { url = "https://files.pythonhosted.org/packages/3c/58/f46decb99415e08d80d915235899cc7e8ba02ee7f9effebc93fcdcd5315b/hypothesis-6.156.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0ca6a4785c058257a729daa218d9c9d06d05db42da4f52484c590f57f7905d5b", size = 744371, upload-time = "2026-07-08T21:54:50.653Z" }, - { url = "https://files.pythonhosted.org/packages/44/ec/c8c19542f6389580e6281f87802849754b8910d29e0a7e36e32ac4e18811/hypothesis-6.156.4-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7338ee15ee84ef994ae3d1a2e71d25c82713bf5ec27f55442755ae15e38369b", size = 1071376, upload-time = "2026-07-08T21:54:54.003Z" }, - { url = "https://files.pythonhosted.org/packages/b5/10/57cc273baf0cfe722eaa903c72db7ca45e7df4cc0780f80cb5dfe50edbbf/hypothesis-6.156.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:539be6819696560c23ff6c0d0af4e7c1ea4936123f4433b511977a79adc371d5", size = 1121429, upload-time = "2026-07-08T21:55:17.323Z" }, - { url = "https://files.pythonhosted.org/packages/68/cf/4b31c31716980972f7b5dfd75fe11021e9b8b6dd09664cc5a82c8c03c2bc/hypothesis-6.156.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b1717bc41d1a0683470f950c565ade33a52c28f600b1aa824d74f651a36e2c7b", size = 640761, upload-time = "2026-07-08T21:54:37.716Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/51/9e/de15052a56c80aa7f4dd677a69cdb22b82df2b53a7f5d0c3fc45b6d5d80b/hypothesis-6.156.5.tar.gz", hash = "sha256:b2780ef6f5bb2b9775763b1d2f978e3cbe31717303c3eb9aa2ada2531c30caac", size = 476278, upload-time = "2026-07-10T14:22:30.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/3c/4e6a1caf42984037e1841e9552b06db96fb26852e1e708a6ddb84b7f3c07/hypothesis-6.156.5-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:aec9566fcf6f062c0730ca864491e888b5a3fd2a6e5652312d41ec700ddd1c13", size = 747969, upload-time = "2026-07-10T14:21:42.536Z" }, + { url = "https://files.pythonhosted.org/packages/73/2f/2898585f3ec2b6e67b8bef9e5293ff4b8a88a1c606987aca29363feae2c3/hypothesis-6.156.5-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:cda44f5da66670907004b21927bcf5d54073f2e502775f42921251ff03e5db4f", size = 743018, upload-time = "2026-07-10T14:22:10.027Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d0/261e73324d8bf887941a332b7d155ee2c2d1bb0bd8dad535569a6b260e8c/hypothesis-6.156.5-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04fc5fb72398f32789c571c542bdcd5ef532dc584b75e24d72cdb27949e64c3a", size = 1070135, upload-time = "2026-07-10T14:21:48.44Z" }, + { url = "https://files.pythonhosted.org/packages/39/02/e5e3a2e5be4b4b6b62fe8002adeeb1b8178fae5722824bc1d889ffe36c72/hypothesis-6.156.5-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a70e62f189a8cc05cbdd9a30e093a6b6ca27a805cff567c0cee834a5982200e9", size = 1121731, upload-time = "2026-07-10T14:21:14.745Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a1/83c4bae9fa63b304e36c379bd7cb3dab4ff8cfd075f14bedd883cdc7146d/hypothesis-6.156.5-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:910dfa8f5b1adc259a4dd73cb06666f632bad2938fb3516d363041d6a14a1b7b", size = 1111410, upload-time = "2026-07-10T14:21:16.199Z" }, + { url = "https://files.pythonhosted.org/packages/d7/3e/ff4621e85fedbfa329c1c4e9ede6cb71a8a12bc93a8e1dfe7e045e50464b/hypothesis-6.156.5-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:78bd5d844ebc49c950596ee50e7afca0da64419b85c382699469a55b65024f6b", size = 1244914, upload-time = "2026-07-10T14:21:22.666Z" }, + { url = "https://files.pythonhosted.org/packages/66/64/de3d3a8be8eb0a2d50c10ddbd92bcc8e8ddab6c1e01c81d081cf4f25aef1/hypothesis-6.156.5-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fafe8e4e62aeb73c1be0f71ccd1b387e701ccbedbde474702da8e4bce01a54e6", size = 1288779, upload-time = "2026-07-10T14:21:43.9Z" }, + { url = "https://files.pythonhosted.org/packages/7d/3c/6767aac371738462e737b08423d7593014943b3d3b75436ed24cb6f35892/hypothesis-6.156.5-cp310-abi3-win32.whl", hash = "sha256:4552dbf25653e3dbdd8dc594a77732c0370ea8ba52c2df64f48a338e63107118", size = 634831, upload-time = "2026-07-10T14:21:12.265Z" }, + { url = "https://files.pythonhosted.org/packages/0d/82/dfde7b1b5d7a0d63325b1009c13910f1e1bd77c2a80162bb95e1ee767c04/hypothesis-6.156.5-cp310-abi3-win_amd64.whl", hash = "sha256:cf647a0d054711e42004004b37376885a50e1b76e5f02c781a3ce674c1e13d5a", size = 640369, upload-time = "2026-07-10T14:21:56.725Z" }, + { url = "https://files.pythonhosted.org/packages/9d/d8/ca43184af179fff81c4a8980f13b146e6303652bea011c0ebe5d8199c13a/hypothesis-6.156.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9c7de49e0567fb956f38c2d469b766365994bf2b23df652df6610cb6ca7bcaca", size = 748942, upload-time = "2026-07-10T14:22:18.457Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ea/869c696ec062ea99e2d08fbb50b07fd2a5bf49d3b0370c6200bb80e7f2a2/hypothesis-6.156.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81207bba26a7e616474acf4ba1e69d53fbe0aa44db7915f02ccd5112da0c5578", size = 743700, upload-time = "2026-07-10T14:21:50.161Z" }, + { url = "https://files.pythonhosted.org/packages/30/ef/80e5cca86e186363872dd49a3e355879b47f36716f46a980cb7c4f3907a9/hypothesis-6.156.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03f1919fa139c86fad6efcb8be3b6614e5309b67f197216d21b59337e2fd04b", size = 1070726, upload-time = "2026-07-10T14:21:36.73Z" }, + { url = "https://files.pythonhosted.org/packages/23/5c/15b15ea52dae1fff4623abe50236c86f52fff4a395d27781c7e1ddb6cdd3/hypothesis-6.156.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d5fbbccaeae692f3cd9c32fd946fed49881385c16d46072b445d2d01b33858c", size = 1121953, upload-time = "2026-07-10T14:21:33.374Z" }, + { url = "https://files.pythonhosted.org/packages/7f/39/03b7b442f549b64871c1aa4847a0adc5ed5bd003b4b4659277c04c477828/hypothesis-6.156.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5cee554b4d0c876215a6bd3bb68d676df9b3666b642a5b952c5c6d777dca6b1a", size = 1245534, upload-time = "2026-07-10T14:21:02.637Z" }, + { url = "https://files.pythonhosted.org/packages/82/c5/958e9d80a36b0e76ff917e6e0d35c864c0b767a5a713d13cd462911596a8/hypothesis-6.156.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:949c9e0fdf0632ab9ac119b99a3b6e610434b5185e86ededa4df0f83f3df4263", size = 1289127, upload-time = "2026-07-10T14:22:04.605Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/7b922c5ba41c4e10239354ad3232e4c8cd7d7c75fee170068bc28f1baedb/hypothesis-6.156.5-cp311-cp311-win_amd64.whl", hash = "sha256:717f167a5fd61097fcf1d31eab2889292f464398b3b1e306c99be2dc91de47ca", size = 640163, upload-time = "2026-07-10T14:21:58.166Z" }, + { url = "https://files.pythonhosted.org/packages/33/ae/f6663fb752e2c186300c4c3f039ac19182382721d5bfb3370ea8820d02f0/hypothesis-6.156.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0622846641949d0f1a925f458768be223b55a8f060b059734f637f3a00869a43", size = 748814, upload-time = "2026-07-10T14:22:11.598Z" }, + { url = "https://files.pythonhosted.org/packages/d0/57/93430b874ac895caa42ff3463e2a5a4e6d3d73c7a8674f8739a0fb5e2707/hypothesis-6.156.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:94f6a94269483a7a53335fa5df2ae2f7c95f76e6a953f511fff03859c2fe616f", size = 741907, upload-time = "2026-07-10T14:21:24.17Z" }, + { url = "https://files.pythonhosted.org/packages/b4/1c/2cc4764ff9d9fe71956a0677133a3e9a6e03bc39633de936a9588260b6ea/hypothesis-6.156.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e226328d39d991d6ec73dc44e717dfa8ec0ed86cb3870995e6ae76b5fec5c157", size = 1069705, upload-time = "2026-07-10T14:21:59.611Z" }, + { url = "https://files.pythonhosted.org/packages/77/09/b0a6ef4124e142ad7d5459840247e5434f85391d0f2431ebdfef265bbadb/hypothesis-6.156.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:750003b04031c9012a0571c14e97ef70111ed42bfbcefab91ba4b619474e32dd", size = 1120948, upload-time = "2026-07-10T14:22:08.406Z" }, + { url = "https://files.pythonhosted.org/packages/a6/df/0b963f188e05c99e72cfb4744500e8124c1fc6a1a97152bc1a09b2a6ab22/hypothesis-6.156.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:012358f9d31fc5b0fadd092fa285d91690a1c6622e75f7120aaec4fd1b12926f", size = 1243853, upload-time = "2026-07-10T14:21:26.89Z" }, + { url = "https://files.pythonhosted.org/packages/1a/e4/62b7c0c45ae9aaf181dc3a355cf042db648141c328b54a40ceae5f5dd2f5/hypothesis-6.156.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:29318faf72ce169b03e90a9e1a8167b2bddb667a653ef66a2f90427b13a191ea", size = 1287779, upload-time = "2026-07-10T14:21:51.67Z" }, + { url = "https://files.pythonhosted.org/packages/bc/90/c9fccb68c072cff3b15695e79f54376df382ae986c2c92d296eef1493306/hypothesis-6.156.5-cp312-cp312-win_amd64.whl", hash = "sha256:3d3a71d67f5309f110855083644b8a0f032adda1c2672b08104470c05a6aac5e", size = 637645, upload-time = "2026-07-10T14:22:26.601Z" }, + { url = "https://files.pythonhosted.org/packages/18/f4/5a6f9f99028a4fb7c9c08e37360193eea174875b05055636dcc6ba63aa62/hypothesis-6.156.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6bc493e3bcb815d1dfe29e0c169f1032c42eea9fd34c7cef734e744d93a17476", size = 749235, upload-time = "2026-07-10T14:22:24.956Z" }, + { url = "https://files.pythonhosted.org/packages/10/e7/141271fe6e4a00825f157e892208a7f4562b62175ffcd0818f813e1135e8/hypothesis-6.156.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5332cbc4bbbc1b4495f534df8c8a7b4fc50ca6a08650b1250896a36c091b0cb2", size = 742068, upload-time = "2026-07-10T14:21:40.954Z" }, + { url = "https://files.pythonhosted.org/packages/8b/6c/62dc31e337c9150d75cec7da7192606711417909175b7d399d52b201d53b/hypothesis-6.156.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8aa21d73ce8238f438eca30e09ab3b7efef37c60c4da21415903d0e45fbffd5", size = 1069905, upload-time = "2026-07-10T14:21:45.399Z" }, + { url = "https://files.pythonhosted.org/packages/2f/c8/9231c8646a5387a80c53f634a22cd5727f7eeb211251b45ef2a3bf0ffa37/hypothesis-6.156.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7123442269105b66924ebcabca92705415db1dd968404f730afd93552840982", size = 1121169, upload-time = "2026-07-10T14:21:30.598Z" }, + { url = "https://files.pythonhosted.org/packages/71/95/a282073b68052868e2ea72b3aef061ab2fd21917f02b31765dbaafa93836/hypothesis-6.156.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8d93f58fa5b77647e5e3b620e2a6d43682adc64a51d4ce7790f0d9ef4c9a9606", size = 1244127, upload-time = "2026-07-10T14:21:20.049Z" }, + { url = "https://files.pythonhosted.org/packages/fe/35/05aaad619f8a50f9d51e9d1b2796787551776df722b247f03c265e101736/hypothesis-6.156.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6b39871997ceefceb4a719eb374a3007aa2768847fa250d987acb2384be8ff5c", size = 1288044, upload-time = "2026-07-10T14:21:53.896Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9d/fc8a3b3c959e0e37462e3d68d2474948b5c7a9439f2e4fbf9583a468b7e2/hypothesis-6.156.5-cp313-cp313-win_amd64.whl", hash = "sha256:a724336107450452e8fa649a3c8f24e2dc01bb7a1f12c475a9f4545f2dc0889c", size = 637919, upload-time = "2026-07-10T14:21:25.423Z" }, + { url = "https://files.pythonhosted.org/packages/ea/9e/ba02f0c8257ed8950487dea86fcc07c44bf5f19b81ab105b58f8f10d6833/hypothesis-6.156.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:0f3eccde4d2de4d0d8343076da8ee694e6fc8a9970e00c751328cc841a90500b", size = 749285, upload-time = "2026-07-10T14:21:21.278Z" }, + { url = "https://files.pythonhosted.org/packages/0d/a0/042091e7a657dfac98fbc8c3c639a35fd387d5d4b4c038bdfdb43af21584/hypothesis-6.156.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c79afa29ef2ef0e96f147ef408ef0d8bbf7a19f218b373913422ac746494ad8e", size = 742288, upload-time = "2026-07-10T14:21:06.373Z" }, + { url = "https://files.pythonhosted.org/packages/99/1b/db9a69bea7fe6684925d27cfe788095a4f0258ef445d95d72dd72522b836/hypothesis-6.156.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8ac71d1b07b692d7e1930d62e1232754f8e7f6507e404f4bcbe16e28a108a47", size = 1070075, upload-time = "2026-07-10T14:21:38.192Z" }, + { url = "https://files.pythonhosted.org/packages/6d/12/d5d5ecaf552ac033d8928d48b5aa042b9e3404a0095830ed61e06402b270/hypothesis-6.156.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff748c5746af6b83b0e5ad35eff0b99e75d021bce57556813062a34e757be48f", size = 1121494, upload-time = "2026-07-10T14:21:10.47Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f0/de2256681ff4dabefbdfaed9f0a951810c35c030d5d5fcdf3424a3e5828f/hypothesis-6.156.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f08d560ecabd4bff4a7f4b34bbc655cdc83b317578c7265e8da0d10b66e272e", size = 1244646, upload-time = "2026-07-10T14:22:14.981Z" }, + { url = "https://files.pythonhosted.org/packages/cf/63/47c7ff0710c03fe321505db83939451962eac87d1d0ce5e5c003ec74b30c/hypothesis-6.156.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ab0598cd43f0e62ca8a58ffde04efd0783fa5795b099959717f9581fe8753355", size = 1288481, upload-time = "2026-07-10T14:22:01.212Z" }, + { url = "https://files.pythonhosted.org/packages/73/91/590491e00ac43940dc42a6845f283cf27bb983f87bb4798f07673eaeef11/hypothesis-6.156.5-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:6f797675b82b7417961dd0d634fe6592d5c7e0e564596a001ec6254a100dbc35", size = 586424, upload-time = "2026-07-10T14:21:46.823Z" }, + { url = "https://files.pythonhosted.org/packages/d9/1e/a2227c775f874c28efc8f12b05823ec3dac81ea8ad721a6afe609a1929f3/hypothesis-6.156.5-cp314-cp314-win_amd64.whl", hash = "sha256:39397347a8b524ea68f2a25dd4178edffe0165ba1cb93190c8ea696070e7b5e7", size = 637739, upload-time = "2026-07-10T14:21:04.769Z" }, + { url = "https://files.pythonhosted.org/packages/c7/d7/0ec1deefcf431285ea00e1e86e8af044f08dc1e9d268415ea2707a1b5bca/hypothesis-6.156.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e8f5093fcaa36e3a5a750b242c41005bf8800f144372dacdcf4c1c4f7ed54e24", size = 747398, upload-time = "2026-07-10T14:21:55.251Z" }, + { url = "https://files.pythonhosted.org/packages/d5/d9/0928982874950fbc276648eba371bea9590af6cfe902bd1adf84bb9a9a04/hypothesis-6.156.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:676cbfb1ff9ad8fa0e10e63ef7e1aec8f1f15c44772375eea6708f988992adaf", size = 740858, upload-time = "2026-07-10T14:22:02.793Z" }, + { url = "https://files.pythonhosted.org/packages/09/57/eb180b67835071e39fbc1d59455683abe9b3bdba3c682be7de739959d02b/hypothesis-6.156.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e34195c4233707fa23abdfc6f1234b6b62d2579d395ed96a56f87e5064226", size = 1069265, upload-time = "2026-07-10T14:21:31.919Z" }, + { url = "https://files.pythonhosted.org/packages/6b/31/6b4e1419fe0e0d1b266b79c48c0e18bc261d43491d46f4dd44594c1f2c42/hypothesis-6.156.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ad53de9310c83bbf0c20901d41421eaf138609314d7421f72db39d39a7f0cf7", size = 1120372, upload-time = "2026-07-10T14:22:20.036Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f8/645ff174828e79183a09f465b29e76331a6f408a00fe6dea3763460353ed/hypothesis-6.156.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5959642a2ba80156baa6e23cc64d40d27e0d160c019c0aae2d2de62a3537963b", size = 1243138, upload-time = "2026-07-10T14:22:16.792Z" }, + { url = "https://files.pythonhosted.org/packages/3f/59/611cfaa2b474d4fe69064ed5a1b7ec4698845755fbe80488ff7cb62efb6b/hypothesis-6.156.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d8ea564a59f3f163f36b7c3522c6bd05c82a508acca5ac6bc5e1b3c265bb8814", size = 1287257, upload-time = "2026-07-10T14:21:08.948Z" }, + { url = "https://files.pythonhosted.org/packages/14/80/0c0a5a6381350b109fd4a696babe90c637a55f5710281059259079cc13b6/hypothesis-6.156.5-cp314-cp314t-win_amd64.whl", hash = "sha256:f1aaebfa3d7c888ad905a6acc933d3093a227b97a136d27ea6d47a531f8bc110", size = 637830, upload-time = "2026-07-10T14:21:29.324Z" }, + { url = "https://files.pythonhosted.org/packages/d0/ad/b034888717705c26860ff808c98298a41540aef0bd25dc395614334e74ea/hypothesis-6.156.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:47a23e44e900cc44f764483158095a138a1e5b4dd5abcd3e2b54ddf56bcc7ba3", size = 749517, upload-time = "2026-07-10T14:21:07.65Z" }, + { url = "https://files.pythonhosted.org/packages/f5/6a/6239e3918cbb48f2fb86420c31b210dde24d692b51da29328a3bafdc0067/hypothesis-6.156.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:268b5df24a92627daa04f241f1fc01331076158927debca953d19a1ac543f3d9", size = 744372, upload-time = "2026-07-10T14:21:18.908Z" }, + { url = "https://files.pythonhosted.org/packages/f3/99/9dcac9f5058e0d0ef5e5372760c7d994c4b739d461bfb24c6554e9ee3b13/hypothesis-6.156.5-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e09354067493aa7a797aacb980a1dc6e063c53cae36d9db8a20bd030d3df435f", size = 1070856, upload-time = "2026-07-10T14:21:39.55Z" }, + { url = "https://files.pythonhosted.org/packages/15/e9/63280b1d04ade37a1be922b6817266b75ecc68a32b6988d6e928415760fe/hypothesis-6.156.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a50062d059fe9f34baaf80aa31c4ef4f42d42fac2a39702d89546a04337a9a7", size = 1122589, upload-time = "2026-07-10T14:21:35.241Z" }, + { url = "https://files.pythonhosted.org/packages/88/6c/6ec6cba54d072b3a7e0ef248a18364d144638115cb95e4681ec9a5cd1290/hypothesis-6.156.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:48173754d2e749649bdd7b978262ef4e597e697a66840e8e168fc0cc20e80ec6", size = 640773, upload-time = "2026-07-10T14:22:13.317Z" }, ] [[package]] @@ -639,27 +641,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/dc/35b341fc554ba02f217fc10da57d1a75168cfbcf75b0ef2202176d4c4f2d/ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566", size = 4755489, upload-time = "2026-06-25T17:20:37.578Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/d9/2d5014f0253ba541d2061d9fa7193f48e941c8b21bb88a7ff9bbe0bd0596/ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078", size = 10839665, upload-time = "2026-06-25T17:19:44.702Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d3/ac1798ba64f670698867fcfc591d50e7e421bef137db564858f619a30fcf/ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b", size = 11208649, upload-time = "2026-06-25T17:19:48.787Z" }, - { url = "https://files.pythonhosted.org/packages/47/47/d3ac899991202095dfcf3d5176be4272642be3cf981a2f1a30f72a2afb95/ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632", size = 10622638, upload-time = "2026-06-25T17:19:51.354Z" }, - { url = "https://files.pythonhosted.org/packages/33/13/4e043fe30aa94d4ff5213a9881fc296d12960f5971b234a5263fdc225312/ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd", size = 10984227, upload-time = "2026-06-25T17:19:54.044Z" }, - { url = "https://files.pythonhosted.org/packages/76/e6/92e7bf40388bc5800073b96564f56264f7e48bfd1a498f5ced6ae6d5a769/ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b", size = 10622882, upload-time = "2026-06-25T17:19:57.037Z" }, - { url = "https://files.pythonhosted.org/packages/13/7a/43460be3f24495a3aa46d4b16873e2c4941b3b5f0b00cf88c03b7b94b339/ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267", size = 11474808, upload-time = "2026-06-25T17:20:00.357Z" }, - { url = "https://files.pythonhosted.org/packages/27/a0/f37077884873221c6b33b4ab49eb18f9f88e54a16a25a5bca59bef46dd66/ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c", size = 12293094, upload-time = "2026-06-25T17:20:03.446Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/165545b60256a9704c21ac0ec4a0d07933b320812f9584836c9f4aca4292/ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae", size = 11526176, upload-time = "2026-06-25T17:20:06.301Z" }, - { url = "https://files.pythonhosted.org/packages/86/b1/a976a136d40ade83ce743578399865f57001003a409acadc0ecbb3051082/ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b", size = 11520767, upload-time = "2026-06-25T17:20:09.191Z" }, - { url = "https://files.pythonhosted.org/packages/19/0f/f032696cb01c9b54c0263fa393474d7758f1cdc021a01b04e3cbc2500999/ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487", size = 11500132, upload-time = "2026-06-25T17:20:13.602Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f4/51b1a14bc69e8c224b15dab9cce8e99b425e0455d462caa2b3c9be2b6a8e/ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3", size = 10943828, upload-time = "2026-06-25T17:20:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/71/4b/fe267640783cd02bf6c5cc290b1df1051be2ec294c678b5c15fe19e52343/ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053", size = 10645418, upload-time = "2026-06-25T17:20:19.4Z" }, - { url = "https://files.pythonhosted.org/packages/b0/c0/a65aa4ec2f5e87a1df32dc3ec1fede434fe3dfd5cbcf3b503cafc676ab54/ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4", size = 11211770, upload-time = "2026-06-25T17:20:22.033Z" }, - { url = "https://files.pythonhosted.org/packages/5a/a4/0caa331d954ae2723d729d351c989cb4ca8b6077d5c6c2cb6de75e98c041/ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460", size = 11618698, upload-time = "2026-06-25T17:20:25.259Z" }, - { url = "https://files.pythonhosted.org/packages/10/9b/5f14927848d2fd4aa891fd88d883788c5a7baba561c7874732364045708c/ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21", size = 10857322, upload-time = "2026-06-25T17:20:28.612Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f0/fe47c501f9dea92a26d788ff98bb5d92ed4cb4c88792c5c88af6b697dc8e/ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415", size = 11993274, upload-time = "2026-06-25T17:20:31.871Z" }, - { url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" }, +version = "0.15.21" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/36/6f65aa9989acdec45d417192d8f4e7921931d8a6cf87ac74bce3eed98a8e/ruff-0.15.21.tar.gz", hash = "sha256:d0cfc841c572283c36548f82664a54ce6565567f1b0d5b4cf2caac693d8b7500", size = 4769401, upload-time = "2026-07-09T20:01:34.005Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/c6/ede15cac6839f3dbce52565c8f5164a8210e669c7bc4decb03e5bdf47d0d/ruff-0.15.21-py3-none-linux_armv6l.whl", hash = "sha256:63ea0e965e5d73c90e95b2434beeafc70820536717f561b32ab6e777cb9bdf5d", size = 10854342, upload-time = "2026-07-09T20:00:53.998Z" }, + { url = "https://files.pythonhosted.org/packages/28/9d/d825b07ee7ea9e2d61df92a860033c94e06e7300d50a1c2653aac27d24fe/ruff-0.15.21-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0f212c5d7d54c01bbfe6dcab02b724a39300f3e34ed7acbe995ccb320a2c58bd", size = 11139539, upload-time = "2026-07-09T20:00:57.809Z" }, + { url = "https://files.pythonhosted.org/packages/f5/de/3b107712e642f063c7a9e0887c427b22cb44097de5aab36c05f2e280670c/ruff-0.15.21-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e6312e41bc96791299614995ea3a977c5857c3b5662b1ecef6755b02b87cb646", size = 10595437, upload-time = "2026-07-09T20:01:00.006Z" }, + { url = "https://files.pythonhosted.org/packages/9a/6f/b4523cc90ba239ede441447a19d0c968846a3012e5a0b0c5b62831a3d5e3/ruff-0.15.21-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01d65b4831c6b2a4ba8ee6faa84049d44d982b7a706e622c4094c509e51673be", size = 10990053, upload-time = "2026-07-09T20:01:02.187Z" }, + { url = "https://files.pythonhosted.org/packages/92/cc/c6a9872a5375f0628875481cf2f66b13d7d865bf3ca2e57f91c7e762d976/ruff-0.15.21-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c5a913a589120ce67933d5d05fd6ddbcc2481c6a054980ee767f7414c72b4fd", size = 10666096, upload-time = "2026-07-09T20:01:04.299Z" }, + { url = "https://files.pythonhosted.org/packages/ab/97/c621f7a17e097f1790fa3af6374138823b330b2d03fc38337945daca212c/ruff-0.15.21-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef04b681d02ad4dc9620f00f83ac5c22f652d0e9a9cfe431d219b16ad5ccc41", size = 11537011, upload-time = "2026-07-09T20:01:06.771Z" }, + { url = "https://files.pythonhosted.org/packages/ea/51/d928727e476e25ccc57c6f449ffd80241a651a973ad949d39cfb2a771d28/ruff-0.15.21-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16d090c0740916594157e75b80d666eab8e78083b39b3b0e1d698f4670a17b86", size = 12347101, upload-time = "2026-07-09T20:01:08.859Z" }, + { url = "https://files.pythonhosted.org/packages/1e/88/8cd62026802b16018ad06931d87997cf795ba2a6239ab659606c87d96bf0/ruff-0.15.21-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a10e74757dd65004d779b73e2f3c5210156d9980b41224d50d2ebcf1db51e67", size = 11572001, upload-time = "2026-07-09T20:01:11.092Z" }, + { url = "https://files.pythonhosted.org/packages/b2/97/f63084cf55444fc110e8cb985ebfcc592af47f597d44453d778cb81bc156/ruff-0.15.21-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bab0905d2f29e0d9fbc3c373ed23db0095edaa3f71f1f4f519ec15134d9e85c8", size = 11549239, upload-time = "2026-07-09T20:01:13.27Z" }, + { url = "https://files.pythonhosted.org/packages/9d/77/f107da4a2874b7715914b03f09ba9c54424de3ff8a1cc5d015d3ee2ce0ac/ruff-0.15.21-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:00eca240af5789fec6fe7df74c088cc1f9644ed83027113468efba7c92b94075", size = 11535340, upload-time = "2026-07-09T20:01:15.206Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e9/601deb322d3303a7bf212b0100ead6f2ee3f6a044d89c30f2f92bf83c731/ruff-0.15.21-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:262ab31557a75141325e32d3357f3597645a7f084e732b6b054dde428ecd9341", size = 10964048, upload-time = "2026-07-09T20:01:17.723Z" }, + { url = "https://files.pythonhosted.org/packages/ea/2e/0f2176d1e99c15192caea19c8c3a0a955246b4cb4de795042eeb616345cd/ruff-0.15.21-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:659c4e7a4212f83306045ec7c5e5a356d16d9a6ef4ae0c7a4d872914fc655d9d", size = 10667055, upload-time = "2026-07-09T20:01:19.73Z" }, + { url = "https://files.pythonhosted.org/packages/48/60/abd74a02e0c4214f12a68becfd30af7165cfdcb0e661ecdc60bbb949c09a/ruff-0.15.21-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9e866eab611a5f959d36df2d10e446973a3610bc42b0c15b31dc27977d59c233", size = 11242043, upload-time = "2026-07-09T20:01:21.947Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c6/583075d8ccabb4b229345edcaf1545eb3d8d6be90f686a479d7e94088bbf/ruff-0.15.21-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e89bc93c0d3803ba870b55c29671bad9dc6d94bb1eb181b056b52eb05b52854f", size = 11648064, upload-time = "2026-07-09T20:01:24.023Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3c/37d0ecb729a7cc2d393ea7dce316fc585680f35d93b8d62139d7d0a3700c/ruff-0.15.21-py3-none-win32.whl", hash = "sha256:01f8d5be84823c172b389e123174f781f9daf86d6c58719d603f941932195cdd", size = 10896555, upload-time = "2026-07-09T20:01:26.941Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b8/e43466b2a6067ce91e669068f6e28d6c719a920f014b070d5c8731725de3/ruff-0.15.21-py3-none-win_amd64.whl", hash = "sha256:d4b8d9a2f0f12b816b50447f6eccb9f4bb01a6b82c86b50fb3b5354b458dc6d3", size = 12038772, upload-time = "2026-07-09T20:01:29.497Z" }, + { url = "https://files.pythonhosted.org/packages/dd/75/e90ab9aeece218a9fc5a5bc3ec97d0ee6bb3c4ff95869463c1de58e29a1c/ruff-0.15.21-py3-none-win_arm64.whl", hash = "sha256:6e83115d4b9377c1cbc13abf0e051f069fab0ef815ea0504a8a008cee24dd0a8", size = 11375265, upload-time = "2026-07-09T20:01:31.772Z" }, ] [[package]] From 4330a7d9dc51d91c3307499be719401d0825e1d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 15:39:56 +0000 Subject: [PATCH 05/11] chore(deps-dev): bump hypothesis in the all-deps group (#451) Bumps the all-deps group with 1 update: [hypothesis](https://github.com/HypothesisWorks/hypothesis). Updates `hypothesis` from 6.156.5 to 6.156.6 - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/v6.156.5...v6.156.6) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.156.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- uv.lock | 106 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/uv.lock b/uv.lock index 715dff68..701593d8 100644 --- a/uv.lock +++ b/uv.lock @@ -215,63 +215,63 @@ wheels = [ [[package]] name = "hypothesis" -version = "6.156.5" +version = "6.156.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/51/9e/de15052a56c80aa7f4dd677a69cdb22b82df2b53a7f5d0c3fc45b6d5d80b/hypothesis-6.156.5.tar.gz", hash = "sha256:b2780ef6f5bb2b9775763b1d2f978e3cbe31717303c3eb9aa2ada2531c30caac", size = 476278, upload-time = "2026-07-10T14:22:30.051Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/3c/4e6a1caf42984037e1841e9552b06db96fb26852e1e708a6ddb84b7f3c07/hypothesis-6.156.5-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:aec9566fcf6f062c0730ca864491e888b5a3fd2a6e5652312d41ec700ddd1c13", size = 747969, upload-time = "2026-07-10T14:21:42.536Z" }, - { url = "https://files.pythonhosted.org/packages/73/2f/2898585f3ec2b6e67b8bef9e5293ff4b8a88a1c606987aca29363feae2c3/hypothesis-6.156.5-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:cda44f5da66670907004b21927bcf5d54073f2e502775f42921251ff03e5db4f", size = 743018, upload-time = "2026-07-10T14:22:10.027Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d0/261e73324d8bf887941a332b7d155ee2c2d1bb0bd8dad535569a6b260e8c/hypothesis-6.156.5-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04fc5fb72398f32789c571c542bdcd5ef532dc584b75e24d72cdb27949e64c3a", size = 1070135, upload-time = "2026-07-10T14:21:48.44Z" }, - { url = "https://files.pythonhosted.org/packages/39/02/e5e3a2e5be4b4b6b62fe8002adeeb1b8178fae5722824bc1d889ffe36c72/hypothesis-6.156.5-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a70e62f189a8cc05cbdd9a30e093a6b6ca27a805cff567c0cee834a5982200e9", size = 1121731, upload-time = "2026-07-10T14:21:14.745Z" }, - { url = "https://files.pythonhosted.org/packages/c1/a1/83c4bae9fa63b304e36c379bd7cb3dab4ff8cfd075f14bedd883cdc7146d/hypothesis-6.156.5-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:910dfa8f5b1adc259a4dd73cb06666f632bad2938fb3516d363041d6a14a1b7b", size = 1111410, upload-time = "2026-07-10T14:21:16.199Z" }, - { url = "https://files.pythonhosted.org/packages/d7/3e/ff4621e85fedbfa329c1c4e9ede6cb71a8a12bc93a8e1dfe7e045e50464b/hypothesis-6.156.5-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:78bd5d844ebc49c950596ee50e7afca0da64419b85c382699469a55b65024f6b", size = 1244914, upload-time = "2026-07-10T14:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/66/64/de3d3a8be8eb0a2d50c10ddbd92bcc8e8ddab6c1e01c81d081cf4f25aef1/hypothesis-6.156.5-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fafe8e4e62aeb73c1be0f71ccd1b387e701ccbedbde474702da8e4bce01a54e6", size = 1288779, upload-time = "2026-07-10T14:21:43.9Z" }, - { url = "https://files.pythonhosted.org/packages/7d/3c/6767aac371738462e737b08423d7593014943b3d3b75436ed24cb6f35892/hypothesis-6.156.5-cp310-abi3-win32.whl", hash = "sha256:4552dbf25653e3dbdd8dc594a77732c0370ea8ba52c2df64f48a338e63107118", size = 634831, upload-time = "2026-07-10T14:21:12.265Z" }, - { url = "https://files.pythonhosted.org/packages/0d/82/dfde7b1b5d7a0d63325b1009c13910f1e1bd77c2a80162bb95e1ee767c04/hypothesis-6.156.5-cp310-abi3-win_amd64.whl", hash = "sha256:cf647a0d054711e42004004b37376885a50e1b76e5f02c781a3ce674c1e13d5a", size = 640369, upload-time = "2026-07-10T14:21:56.725Z" }, - { url = "https://files.pythonhosted.org/packages/9d/d8/ca43184af179fff81c4a8980f13b146e6303652bea011c0ebe5d8199c13a/hypothesis-6.156.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9c7de49e0567fb956f38c2d469b766365994bf2b23df652df6610cb6ca7bcaca", size = 748942, upload-time = "2026-07-10T14:22:18.457Z" }, - { url = "https://files.pythonhosted.org/packages/5f/ea/869c696ec062ea99e2d08fbb50b07fd2a5bf49d3b0370c6200bb80e7f2a2/hypothesis-6.156.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81207bba26a7e616474acf4ba1e69d53fbe0aa44db7915f02ccd5112da0c5578", size = 743700, upload-time = "2026-07-10T14:21:50.161Z" }, - { url = "https://files.pythonhosted.org/packages/30/ef/80e5cca86e186363872dd49a3e355879b47f36716f46a980cb7c4f3907a9/hypothesis-6.156.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03f1919fa139c86fad6efcb8be3b6614e5309b67f197216d21b59337e2fd04b", size = 1070726, upload-time = "2026-07-10T14:21:36.73Z" }, - { url = "https://files.pythonhosted.org/packages/23/5c/15b15ea52dae1fff4623abe50236c86f52fff4a395d27781c7e1ddb6cdd3/hypothesis-6.156.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d5fbbccaeae692f3cd9c32fd946fed49881385c16d46072b445d2d01b33858c", size = 1121953, upload-time = "2026-07-10T14:21:33.374Z" }, - { url = "https://files.pythonhosted.org/packages/7f/39/03b7b442f549b64871c1aa4847a0adc5ed5bd003b4b4659277c04c477828/hypothesis-6.156.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5cee554b4d0c876215a6bd3bb68d676df9b3666b642a5b952c5c6d777dca6b1a", size = 1245534, upload-time = "2026-07-10T14:21:02.637Z" }, - { url = "https://files.pythonhosted.org/packages/82/c5/958e9d80a36b0e76ff917e6e0d35c864c0b767a5a713d13cd462911596a8/hypothesis-6.156.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:949c9e0fdf0632ab9ac119b99a3b6e610434b5185e86ededa4df0f83f3df4263", size = 1289127, upload-time = "2026-07-10T14:22:04.605Z" }, - { url = "https://files.pythonhosted.org/packages/70/99/7b922c5ba41c4e10239354ad3232e4c8cd7d7c75fee170068bc28f1baedb/hypothesis-6.156.5-cp311-cp311-win_amd64.whl", hash = "sha256:717f167a5fd61097fcf1d31eab2889292f464398b3b1e306c99be2dc91de47ca", size = 640163, upload-time = "2026-07-10T14:21:58.166Z" }, - { url = "https://files.pythonhosted.org/packages/33/ae/f6663fb752e2c186300c4c3f039ac19182382721d5bfb3370ea8820d02f0/hypothesis-6.156.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0622846641949d0f1a925f458768be223b55a8f060b059734f637f3a00869a43", size = 748814, upload-time = "2026-07-10T14:22:11.598Z" }, - { url = "https://files.pythonhosted.org/packages/d0/57/93430b874ac895caa42ff3463e2a5a4e6d3d73c7a8674f8739a0fb5e2707/hypothesis-6.156.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:94f6a94269483a7a53335fa5df2ae2f7c95f76e6a953f511fff03859c2fe616f", size = 741907, upload-time = "2026-07-10T14:21:24.17Z" }, - { url = "https://files.pythonhosted.org/packages/b4/1c/2cc4764ff9d9fe71956a0677133a3e9a6e03bc39633de936a9588260b6ea/hypothesis-6.156.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e226328d39d991d6ec73dc44e717dfa8ec0ed86cb3870995e6ae76b5fec5c157", size = 1069705, upload-time = "2026-07-10T14:21:59.611Z" }, - { url = "https://files.pythonhosted.org/packages/77/09/b0a6ef4124e142ad7d5459840247e5434f85391d0f2431ebdfef265bbadb/hypothesis-6.156.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:750003b04031c9012a0571c14e97ef70111ed42bfbcefab91ba4b619474e32dd", size = 1120948, upload-time = "2026-07-10T14:22:08.406Z" }, - { url = "https://files.pythonhosted.org/packages/a6/df/0b963f188e05c99e72cfb4744500e8124c1fc6a1a97152bc1a09b2a6ab22/hypothesis-6.156.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:012358f9d31fc5b0fadd092fa285d91690a1c6622e75f7120aaec4fd1b12926f", size = 1243853, upload-time = "2026-07-10T14:21:26.89Z" }, - { url = "https://files.pythonhosted.org/packages/1a/e4/62b7c0c45ae9aaf181dc3a355cf042db648141c328b54a40ceae5f5dd2f5/hypothesis-6.156.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:29318faf72ce169b03e90a9e1a8167b2bddb667a653ef66a2f90427b13a191ea", size = 1287779, upload-time = "2026-07-10T14:21:51.67Z" }, - { url = "https://files.pythonhosted.org/packages/bc/90/c9fccb68c072cff3b15695e79f54376df382ae986c2c92d296eef1493306/hypothesis-6.156.5-cp312-cp312-win_amd64.whl", hash = "sha256:3d3a71d67f5309f110855083644b8a0f032adda1c2672b08104470c05a6aac5e", size = 637645, upload-time = "2026-07-10T14:22:26.601Z" }, - { url = "https://files.pythonhosted.org/packages/18/f4/5a6f9f99028a4fb7c9c08e37360193eea174875b05055636dcc6ba63aa62/hypothesis-6.156.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6bc493e3bcb815d1dfe29e0c169f1032c42eea9fd34c7cef734e744d93a17476", size = 749235, upload-time = "2026-07-10T14:22:24.956Z" }, - { url = "https://files.pythonhosted.org/packages/10/e7/141271fe6e4a00825f157e892208a7f4562b62175ffcd0818f813e1135e8/hypothesis-6.156.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5332cbc4bbbc1b4495f534df8c8a7b4fc50ca6a08650b1250896a36c091b0cb2", size = 742068, upload-time = "2026-07-10T14:21:40.954Z" }, - { url = "https://files.pythonhosted.org/packages/8b/6c/62dc31e337c9150d75cec7da7192606711417909175b7d399d52b201d53b/hypothesis-6.156.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8aa21d73ce8238f438eca30e09ab3b7efef37c60c4da21415903d0e45fbffd5", size = 1069905, upload-time = "2026-07-10T14:21:45.399Z" }, - { url = "https://files.pythonhosted.org/packages/2f/c8/9231c8646a5387a80c53f634a22cd5727f7eeb211251b45ef2a3bf0ffa37/hypothesis-6.156.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7123442269105b66924ebcabca92705415db1dd968404f730afd93552840982", size = 1121169, upload-time = "2026-07-10T14:21:30.598Z" }, - { url = "https://files.pythonhosted.org/packages/71/95/a282073b68052868e2ea72b3aef061ab2fd21917f02b31765dbaafa93836/hypothesis-6.156.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8d93f58fa5b77647e5e3b620e2a6d43682adc64a51d4ce7790f0d9ef4c9a9606", size = 1244127, upload-time = "2026-07-10T14:21:20.049Z" }, - { url = "https://files.pythonhosted.org/packages/fe/35/05aaad619f8a50f9d51e9d1b2796787551776df722b247f03c265e101736/hypothesis-6.156.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6b39871997ceefceb4a719eb374a3007aa2768847fa250d987acb2384be8ff5c", size = 1288044, upload-time = "2026-07-10T14:21:53.896Z" }, - { url = "https://files.pythonhosted.org/packages/e7/9d/fc8a3b3c959e0e37462e3d68d2474948b5c7a9439f2e4fbf9583a468b7e2/hypothesis-6.156.5-cp313-cp313-win_amd64.whl", hash = "sha256:a724336107450452e8fa649a3c8f24e2dc01bb7a1f12c475a9f4545f2dc0889c", size = 637919, upload-time = "2026-07-10T14:21:25.423Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/ba02f0c8257ed8950487dea86fcc07c44bf5f19b81ab105b58f8f10d6833/hypothesis-6.156.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:0f3eccde4d2de4d0d8343076da8ee694e6fc8a9970e00c751328cc841a90500b", size = 749285, upload-time = "2026-07-10T14:21:21.278Z" }, - { url = "https://files.pythonhosted.org/packages/0d/a0/042091e7a657dfac98fbc8c3c639a35fd387d5d4b4c038bdfdb43af21584/hypothesis-6.156.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c79afa29ef2ef0e96f147ef408ef0d8bbf7a19f218b373913422ac746494ad8e", size = 742288, upload-time = "2026-07-10T14:21:06.373Z" }, - { url = "https://files.pythonhosted.org/packages/99/1b/db9a69bea7fe6684925d27cfe788095a4f0258ef445d95d72dd72522b836/hypothesis-6.156.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8ac71d1b07b692d7e1930d62e1232754f8e7f6507e404f4bcbe16e28a108a47", size = 1070075, upload-time = "2026-07-10T14:21:38.192Z" }, - { url = "https://files.pythonhosted.org/packages/6d/12/d5d5ecaf552ac033d8928d48b5aa042b9e3404a0095830ed61e06402b270/hypothesis-6.156.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff748c5746af6b83b0e5ad35eff0b99e75d021bce57556813062a34e757be48f", size = 1121494, upload-time = "2026-07-10T14:21:10.47Z" }, - { url = "https://files.pythonhosted.org/packages/f9/f0/de2256681ff4dabefbdfaed9f0a951810c35c030d5d5fcdf3424a3e5828f/hypothesis-6.156.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f08d560ecabd4bff4a7f4b34bbc655cdc83b317578c7265e8da0d10b66e272e", size = 1244646, upload-time = "2026-07-10T14:22:14.981Z" }, - { url = "https://files.pythonhosted.org/packages/cf/63/47c7ff0710c03fe321505db83939451962eac87d1d0ce5e5c003ec74b30c/hypothesis-6.156.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ab0598cd43f0e62ca8a58ffde04efd0783fa5795b099959717f9581fe8753355", size = 1288481, upload-time = "2026-07-10T14:22:01.212Z" }, - { url = "https://files.pythonhosted.org/packages/73/91/590491e00ac43940dc42a6845f283cf27bb983f87bb4798f07673eaeef11/hypothesis-6.156.5-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:6f797675b82b7417961dd0d634fe6592d5c7e0e564596a001ec6254a100dbc35", size = 586424, upload-time = "2026-07-10T14:21:46.823Z" }, - { url = "https://files.pythonhosted.org/packages/d9/1e/a2227c775f874c28efc8f12b05823ec3dac81ea8ad721a6afe609a1929f3/hypothesis-6.156.5-cp314-cp314-win_amd64.whl", hash = "sha256:39397347a8b524ea68f2a25dd4178edffe0165ba1cb93190c8ea696070e7b5e7", size = 637739, upload-time = "2026-07-10T14:21:04.769Z" }, - { url = "https://files.pythonhosted.org/packages/c7/d7/0ec1deefcf431285ea00e1e86e8af044f08dc1e9d268415ea2707a1b5bca/hypothesis-6.156.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e8f5093fcaa36e3a5a750b242c41005bf8800f144372dacdcf4c1c4f7ed54e24", size = 747398, upload-time = "2026-07-10T14:21:55.251Z" }, - { url = "https://files.pythonhosted.org/packages/d5/d9/0928982874950fbc276648eba371bea9590af6cfe902bd1adf84bb9a9a04/hypothesis-6.156.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:676cbfb1ff9ad8fa0e10e63ef7e1aec8f1f15c44772375eea6708f988992adaf", size = 740858, upload-time = "2026-07-10T14:22:02.793Z" }, - { url = "https://files.pythonhosted.org/packages/09/57/eb180b67835071e39fbc1d59455683abe9b3bdba3c682be7de739959d02b/hypothesis-6.156.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e34195c4233707fa23abdfc6f1234b6b62d2579d395ed96a56f87e5064226", size = 1069265, upload-time = "2026-07-10T14:21:31.919Z" }, - { url = "https://files.pythonhosted.org/packages/6b/31/6b4e1419fe0e0d1b266b79c48c0e18bc261d43491d46f4dd44594c1f2c42/hypothesis-6.156.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ad53de9310c83bbf0c20901d41421eaf138609314d7421f72db39d39a7f0cf7", size = 1120372, upload-time = "2026-07-10T14:22:20.036Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f8/645ff174828e79183a09f465b29e76331a6f408a00fe6dea3763460353ed/hypothesis-6.156.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5959642a2ba80156baa6e23cc64d40d27e0d160c019c0aae2d2de62a3537963b", size = 1243138, upload-time = "2026-07-10T14:22:16.792Z" }, - { url = "https://files.pythonhosted.org/packages/3f/59/611cfaa2b474d4fe69064ed5a1b7ec4698845755fbe80488ff7cb62efb6b/hypothesis-6.156.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d8ea564a59f3f163f36b7c3522c6bd05c82a508acca5ac6bc5e1b3c265bb8814", size = 1287257, upload-time = "2026-07-10T14:21:08.948Z" }, - { url = "https://files.pythonhosted.org/packages/14/80/0c0a5a6381350b109fd4a696babe90c637a55f5710281059259079cc13b6/hypothesis-6.156.5-cp314-cp314t-win_amd64.whl", hash = "sha256:f1aaebfa3d7c888ad905a6acc933d3093a227b97a136d27ea6d47a531f8bc110", size = 637830, upload-time = "2026-07-10T14:21:29.324Z" }, - { url = "https://files.pythonhosted.org/packages/d0/ad/b034888717705c26860ff808c98298a41540aef0bd25dc395614334e74ea/hypothesis-6.156.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:47a23e44e900cc44f764483158095a138a1e5b4dd5abcd3e2b54ddf56bcc7ba3", size = 749517, upload-time = "2026-07-10T14:21:07.65Z" }, - { url = "https://files.pythonhosted.org/packages/f5/6a/6239e3918cbb48f2fb86420c31b210dde24d692b51da29328a3bafdc0067/hypothesis-6.156.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:268b5df24a92627daa04f241f1fc01331076158927debca953d19a1ac543f3d9", size = 744372, upload-time = "2026-07-10T14:21:18.908Z" }, - { url = "https://files.pythonhosted.org/packages/f3/99/9dcac9f5058e0d0ef5e5372760c7d994c4b739d461bfb24c6554e9ee3b13/hypothesis-6.156.5-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e09354067493aa7a797aacb980a1dc6e063c53cae36d9db8a20bd030d3df435f", size = 1070856, upload-time = "2026-07-10T14:21:39.55Z" }, - { url = "https://files.pythonhosted.org/packages/15/e9/63280b1d04ade37a1be922b6817266b75ecc68a32b6988d6e928415760fe/hypothesis-6.156.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a50062d059fe9f34baaf80aa31c4ef4f42d42fac2a39702d89546a04337a9a7", size = 1122589, upload-time = "2026-07-10T14:21:35.241Z" }, - { url = "https://files.pythonhosted.org/packages/88/6c/6ec6cba54d072b3a7e0ef248a18364d144638115cb95e4681ec9a5cd1290/hypothesis-6.156.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:48173754d2e749649bdd7b978262ef4e597e697a66840e8e168fc0cc20e80ec6", size = 640773, upload-time = "2026-07-10T14:22:13.317Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/20/83/8dbe89bdb8c6f25a7a52e7898af6d82fe35dfef08e5c702f6e33231ce6c6/hypothesis-6.156.6.tar.gz", hash = "sha256:96de02faefa3ce079873541da96f42595583bb001e8e4219294ed7d4501cc4cc", size = 476304, upload-time = "2026-07-10T20:56:49.96Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/dc/0c2a851f06c91d5ac9ef0f3b9615efc1ed650411d2eee23b6334f491c85e/hypothesis-6.156.6-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:caf6a93d011c10972da111c38ceb34ced20feaa8581e2b350c0655b022e27875", size = 747998, upload-time = "2026-07-10T20:56:16.311Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f8/59203ca978ab51595d12d6bc7e7a63300d7373431ab42ca3f1742e45db68/hypothesis-6.156.6-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:07f2bc9df1aeba80e12029c1618e2ee54abc440068c305d7075ffd6b85251843", size = 743073, upload-time = "2026-07-10T20:55:36.825Z" }, + { url = "https://files.pythonhosted.org/packages/68/d8/86a0023740434098d1b187a62bd5f99b198f098fb43e7fc58342283a8270/hypothesis-6.156.6-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7baca17f4803ad4aa151732326f3990baf54c3127df44aa872ac5bdf8a98a9a6", size = 1070169, upload-time = "2026-07-10T20:55:49.47Z" }, + { url = "https://files.pythonhosted.org/packages/9b/82/673453915fd0c67673f35a4876ba88f48c621335f293f3537d77b27d4286/hypothesis-6.156.6-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8083806645f84243aade727f4978185caaa0b7190af4318673999ee15fdbf424", size = 1121760, upload-time = "2026-07-10T20:55:53.502Z" }, + { url = "https://files.pythonhosted.org/packages/8a/c3/3a5557f52912f2fecc6ed59642dcf80dd8e89d0d9664502b68e23d66bf3d/hypothesis-6.156.6-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a922eedcd8618f9c2e17b79fa7b3f3f0b2df34e201958611cc3f0f46cca33c10", size = 1111440, upload-time = "2026-07-10T20:55:43.054Z" }, + { url = "https://files.pythonhosted.org/packages/38/a6/ae636d4ca7f996a1ccb4b3d5997d949f1718fba52b01559b3ab53b237b3f/hypothesis-6.156.6-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5291bd33c4704d274d7c214d5c200e77f372a06644f5cbbe96dcbe53cb2fbf10", size = 1244944, upload-time = "2026-07-10T20:55:56.109Z" }, + { url = "https://files.pythonhosted.org/packages/1e/79/c425d22d734be0268ca60d120c6296299e4220a1783cb1a4cc76232807bb/hypothesis-6.156.6-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55f3ec50161b4a95bae63bff2b5166e45935b493013d3be30ede279bf6192318", size = 1288808, upload-time = "2026-07-10T20:56:06.249Z" }, + { url = "https://files.pythonhosted.org/packages/c5/3a/cc9f479d22cbdd36ddfc55a978378eddadd183b09339ebdb81be33bb18e7/hypothesis-6.156.6-cp310-abi3-win32.whl", hash = "sha256:e96570ca5cdd9a5f2ff9e80a6fb2fd5420ebf33b833d7de5b09b6ebb26a3eb6c", size = 634868, upload-time = "2026-07-10T20:55:37.959Z" }, + { url = "https://files.pythonhosted.org/packages/d6/89/2008d287289841a936456cb13443ca89d88da6e4527d611d482e9544164d/hypothesis-6.156.6-cp310-abi3-win_amd64.whl", hash = "sha256:32710718c22fe8c5571464e898bb87d282837b02617d6ad68130abf7cb4843cb", size = 640382, upload-time = "2026-07-10T20:55:30.634Z" }, + { url = "https://files.pythonhosted.org/packages/13/64/e4a0796190d8089e85f06731e21fdddd7e8edd3a4e562101527a048e21c4/hypothesis-6.156.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5baec7943a14d106e982121dd4f74cfc5ef45e37c17f94fe49338d3d1377f38c", size = 748988, upload-time = "2026-07-10T20:56:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a2/4a789b286cd2cced31992e1f683036b51dd6909b934ea007ffb43aa3a32f/hypothesis-6.156.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b5f519905ddeb10e23b8ba2c254541a5b1a8f146fe0551be94d972f4a77226f4", size = 743754, upload-time = "2026-07-10T20:56:09.113Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f7/3dd36c1c03d24ae3ffc3c5b0eca8cc4ae90c07abc320f76509eceb37019a/hypothesis-6.156.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c108655960b58ded3ca71b2dc5c69fb2ba7e9c723aeb6106facec3892d09087", size = 1070732, upload-time = "2026-07-10T20:56:28.738Z" }, + { url = "https://files.pythonhosted.org/packages/57/51/befc4b816b471078034a875eb1ef69e0411ab84bcce582b4be173258785a/hypothesis-6.156.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c8d37bebb6924729bc0bbf5852689df568842948abe4d93dd0ad3377adf76fa", size = 1121988, upload-time = "2026-07-10T20:56:07.676Z" }, + { url = "https://files.pythonhosted.org/packages/05/b7/a796f5e3e4b7cb911ff346008d49720296d1f4073490b8bc1cce6b3fbb07/hypothesis-6.156.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:74137bef6d502305c3648b2ed1a9bb4bc05fb1025e96b30a2c092204c40fe097", size = 1245596, upload-time = "2026-07-10T20:55:50.662Z" }, + { url = "https://files.pythonhosted.org/packages/37/65/849c4cba44a6f6cc888fd931124429b24180234ccc4883abab8cad5fcfcb/hypothesis-6.156.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5e0afdf79cceed20fcf0a9fb80d4064a9b2b53d4d4eecbac0e21208a13f5a31b", size = 1289172, upload-time = "2026-07-10T20:55:58.915Z" }, + { url = "https://files.pythonhosted.org/packages/13/03/7106a110df29eb631d66776e8aa8128f82f04a9dd2b6b22b612e6025e3a2/hypothesis-6.156.6-cp311-cp311-win_amd64.whl", hash = "sha256:84dc89caaf741a02f904ca7bd02b1af99650c75552868162290208aeecb70858", size = 640222, upload-time = "2026-07-10T20:56:10.396Z" }, + { url = "https://files.pythonhosted.org/packages/8c/45/9f009005b9c796f4a40424484ac7e70847bc088456fd940a937f96bb4b6d/hypothesis-6.156.6-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a2a728b514fceb81e3f0464508911d5220fd74dadc3270f859427a686b60c4cf", size = 748844, upload-time = "2026-07-10T20:56:38.036Z" }, + { url = "https://files.pythonhosted.org/packages/02/2f/4d852bb8a9c73a68b18eca9b5b085285282122166e158f4d2a477639bfee/hypothesis-6.156.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7489b9a8f9df8227edd6c7cd8b9ccfab2483bab24da6a474c175973ca2294f58", size = 741936, upload-time = "2026-07-10T20:55:27.539Z" }, + { url = "https://files.pythonhosted.org/packages/74/89/b9968070ae042f9bf3149bb6ba6399d5f28f452e0fb7f638cafc69ff0b9a/hypothesis-6.156.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42760873d6db1069d6edbaa355a61b9078a9950259efcfc72fc695741d7db7cd", size = 1069749, upload-time = "2026-07-10T20:56:43.017Z" }, + { url = "https://files.pythonhosted.org/packages/00/a9/753806f5292b40aeab1d269e408e3a7e85be3c0d88828fb78ab4a34d6626/hypothesis-6.156.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4e66aaa7385538a5d617174d47c198ee807f06de99e282a67c6cb724c69340d", size = 1120983, upload-time = "2026-07-10T20:56:25.424Z" }, + { url = "https://files.pythonhosted.org/packages/85/88/8386d064d680be27e936eba94f1448bc93ef6fa05473ee5034139f1c4284/hypothesis-6.156.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:08796b674c0b31a5dd4119b2173823390055921588d13eb77324e861b00fd7f8", size = 1243911, upload-time = "2026-07-10T20:55:54.799Z" }, + { url = "https://files.pythonhosted.org/packages/c1/8c/7524c1e5279e7728eb47c99f2357cbc5f08ae92e9bce49bf50118b53f9c9/hypothesis-6.156.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4ca8cc26ea2d31d22cf7710e92951cfaa921f0f8aa1b6db33a5176335f583a4f", size = 1287806, upload-time = "2026-07-10T20:56:02.176Z" }, + { url = "https://files.pythonhosted.org/packages/5a/b3/c347ad913e1c5f2988956fe17826c0400b4ce470b973e6c248e97b6a0acf/hypothesis-6.156.6-cp312-cp312-win_amd64.whl", hash = "sha256:c3363d3fb8015594636689572510bb6090602d8e8e838a5693c2d52d3b5b09d8", size = 637679, upload-time = "2026-07-10T20:55:39.056Z" }, + { url = "https://files.pythonhosted.org/packages/70/5d/9583fe153573523dac27226c89e041a86ad4aeeae08c868160cbb93d39d2/hypothesis-6.156.6-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:59a8def90d9a5a9b67e1ac529e903a2363ceb6cf873c209da6b4284c5daab671", size = 749264, upload-time = "2026-07-10T20:56:46.118Z" }, + { url = "https://files.pythonhosted.org/packages/86/35/e4113d06769b544f0fb77ffea9195b598b4c56a298905c21fd47c4eed388/hypothesis-6.156.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c574c3224563d730848bc5d1ef1683c4f83993400c0167899fe328f4bfcd4725", size = 742095, upload-time = "2026-07-10T20:56:41.412Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5c/a47666ede10384e8978722cade7ab96a42df71d2ab577317092d0fed7c8a/hypothesis-6.156.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01bb8270c46b3ef53b0c2d23ff613ea506d609d06f936d823ea57c58b66b05f7", size = 1069917, upload-time = "2026-07-10T20:56:04.845Z" }, + { url = "https://files.pythonhosted.org/packages/79/93/75f6057dadd9dc0134f37c08d5d14d04d3cd7374debbcb0cc4569c6712f1/hypothesis-6.156.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4ea6559c13606e13b645927f2e0906e52b5ac5d99b40d3abaaeb2e8c7ceeb75", size = 1121204, upload-time = "2026-07-10T20:55:52.008Z" }, + { url = "https://files.pythonhosted.org/packages/62/87/308efef08bc60d1e673d035e8ca8e9663f4b6b3ba519c3cdebf6583c2b76/hypothesis-6.156.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2d47054d0230f0dd9b6868fc030126c7a6c25527144272ff376cc4e9c39f7540", size = 1244168, upload-time = "2026-07-10T20:55:40.288Z" }, + { url = "https://files.pythonhosted.org/packages/3b/66/de8fff5bd9a40a4056dafbe7f904887ef12632282bbbac90f1977c30dd3b/hypothesis-6.156.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:050c8c0815f88d47dd0875a92698d20d61639b7b721ee043a6d687c7f14ff7d8", size = 1288127, upload-time = "2026-07-10T20:56:00.541Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8d/794fb26e1fd3ff004978f8f18b7aa7e1c2270ba72e1f977b987a812064f8/hypothesis-6.156.6-cp313-cp313-win_amd64.whl", hash = "sha256:f0d73edab7b8a0051b3634f2d04d62b7e7282f8f274963b11188ee4957d672ef", size = 637954, upload-time = "2026-07-10T20:56:33.35Z" }, + { url = "https://files.pythonhosted.org/packages/a5/be/5b4b27984cb43c60e95f570b069660335dad34cb67f7d226017c5d35d31e/hypothesis-6.156.6-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:34a70a7b8226e34d658072d8fb81d03f97f0a75ceb536329a321b94ce2232fd6", size = 749312, upload-time = "2026-07-10T20:55:46.902Z" }, + { url = "https://files.pythonhosted.org/packages/31/11/709cceffc28666c9d4cb75ffc6df5ce30db8c7dd5cc2c8b38a2fd837427f/hypothesis-6.156.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f1969646beead7d8cf6a2537d2765af89d73056e2cb218e7fae92b83802250a3", size = 742332, upload-time = "2026-07-10T20:56:30.254Z" }, + { url = "https://files.pythonhosted.org/packages/84/52/cfc79b13d8dd3cd6de6b9df921c557efe8528a9c90a3a7cd93b37188d57e/hypothesis-6.156.6-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbc2ec7b7d905e6b6ec1635f6340bfa52aaab718101c59f052bc012a6b486cd8", size = 1070109, upload-time = "2026-07-10T20:55:48.244Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ac/1da4def1f006b5ad01187ff96379e24c37439d659ec10c3e944c03436c0f/hypothesis-6.156.6-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9367ae25dfa6dc1af37904785e43c4f8fe1c4118cafdc2f06514154fbdd90992", size = 1121528, upload-time = "2026-07-10T20:56:39.665Z" }, + { url = "https://files.pythonhosted.org/packages/68/47/744e4f5e3d635dea20dbedf3fa486e2a6fa5210e0a52a0d5c4da56babd84/hypothesis-6.156.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:455f09107ec07c78f2a83cb8fc19e23879c9d51cdc831de6f9cb6ec4059cb9af", size = 1244690, upload-time = "2026-07-10T20:56:31.854Z" }, + { url = "https://files.pythonhosted.org/packages/25/8a/42252fcd5e521d140dac532f29c2a13ca8f22908cb545ffdd64b5e225680/hypothesis-6.156.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c76634c45a3ceee4c4fdfed39aebd08b8b822ec8b0c556877ef82846fd777730", size = 1288519, upload-time = "2026-07-10T20:56:03.429Z" }, + { url = "https://files.pythonhosted.org/packages/44/e7/176df9e47cf583d2b8d234b78c0aac3a47075ad5d147e60b2c21a1338bb1/hypothesis-6.156.6-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:eb7e9f8343bc6b948937e6ec12e6879ed25a17b53ceccbd2b84adadd3d511698", size = 586452, upload-time = "2026-07-10T20:56:22.285Z" }, + { url = "https://files.pythonhosted.org/packages/8c/75/2c8a0411bbe76429f3ae738ef9a00107201bf6146d9534350014ce369d98/hypothesis-6.156.6-cp314-cp314-win_amd64.whl", hash = "sha256:f9631cd604ae6032c3edf99160dc1b9e33873f2e52762246b24f07fb758652ae", size = 637774, upload-time = "2026-07-10T20:56:34.97Z" }, + { url = "https://files.pythonhosted.org/packages/2a/22/8115005e9aa72c8d63d90e9db5e0b8425fd8950fbc5d6e332805d4d32c9e/hypothesis-6.156.6-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:1f81163d36d3763b09ffaef7c3a71e88174ca3e6816201fca9d1d159f448fdb5", size = 747428, upload-time = "2026-07-10T20:56:44.611Z" }, + { url = "https://files.pythonhosted.org/packages/e8/c2/66bfe9337f4a4b1f7754ee6d01d950280152a81d0d797e6c1d9eb0909750/hypothesis-6.156.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:556b905767e36147918634a64356aa05d8c956576f00aee01eb351678f193908", size = 740889, upload-time = "2026-07-10T20:55:57.656Z" }, + { url = "https://files.pythonhosted.org/packages/95/3b/69f45af2d4f0950b7d1af3cdbdd800b88a6c2370331481eda79d6171fbe3/hypothesis-6.156.6-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3f2604b28d16d696aaaf4954d20f907b27e54034df98e64746a20c74c319f03", size = 1069270, upload-time = "2026-07-10T20:56:12.024Z" }, + { url = "https://files.pythonhosted.org/packages/f8/43/6b2549885da08f5e50ba34fb8e0d0a60b2f190ffd516fac220f8db5b5869/hypothesis-6.156.6-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffe012ad66dbe7b8e8ddef6f6992ab1b36719ea64430c2bf1ff7135521052a15", size = 1120409, upload-time = "2026-07-10T20:55:34.551Z" }, + { url = "https://files.pythonhosted.org/packages/70/97/745c778c3eb29befa2367b1ded8437eecfbbe6932359d0f831275bc32170/hypothesis-6.156.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5bfa3c7b758f7278081c6bfec5f89b43c4eb075c0c9eb095323f7a9eb019b513", size = 1243111, upload-time = "2026-07-10T20:56:17.83Z" }, + { url = "https://files.pythonhosted.org/packages/ab/d7/c5ec6a442dc9b822f47064bda4b6d3e739dccdd1c5bf44c9a57fb6136830/hypothesis-6.156.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d0db1f4573800c618773622f03cb6533bb3377430ef938c9476ba10c39d22591", size = 1287262, upload-time = "2026-07-10T20:56:23.749Z" }, + { url = "https://files.pythonhosted.org/packages/11/0c/c134d61710e14b68b010215dcf6bd57d2ec05cd169dff8bfab8fefc2d410/hypothesis-6.156.6-cp314-cp314t-win_amd64.whl", hash = "sha256:38cd0c4a7b9f809f1e23a4d15adfa9c5d99869b9afc327350a5e563350b78e48", size = 637862, upload-time = "2026-07-10T20:56:13.347Z" }, + { url = "https://files.pythonhosted.org/packages/59/9c/b94f3a31665527b6181616b72990fcf8d6d5fa82b4187aab104ab5f548f0/hypothesis-6.156.6-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8893b4da90e06828846c1b100c3414a7729d047a020d854c0899ae9339df0e70", size = 749575, upload-time = "2026-07-10T20:55:29.371Z" }, + { url = "https://files.pythonhosted.org/packages/21/74/dcf695f79f526543ae5d0f8c1325508e9fe990a996c0e0853129a9a5d81d/hypothesis-6.156.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7fc0b7df9b28d028e4cc295b2ac8fbbbc22e090a23382c92fff5e37696be74f", size = 744351, upload-time = "2026-07-10T20:56:36.46Z" }, + { url = "https://files.pythonhosted.org/packages/11/d3/5bff4c55c6995a6c43f66ec8e5866b56e34f03837fd0be0e4922f3bab168/hypothesis-6.156.6-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38ed3178526382d392d04ad699ad7a2e53845e521a09d40f1cbbc1e1ff63ba48", size = 1070916, upload-time = "2026-07-10T20:56:19.256Z" }, + { url = "https://files.pythonhosted.org/packages/ba/af/5ed42117a69221ea118caaff933d8212039a0ac0bc15afa915635f13984c/hypothesis-6.156.6-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ad94e28aabf4db0d479297d43b8a2a01e7caaa9bdfccfdac7a4a3717e05b993", size = 1122625, upload-time = "2026-07-10T20:56:14.758Z" }, + { url = "https://files.pythonhosted.org/packages/3b/d3/02499badc6e3f3e980941021edf5fd780c895d8d08c9015e78516340ed83/hypothesis-6.156.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:983a5cfd955994bffc7eb02976241f7a1f3c2d94dbc3389430c45858fa5c1ae0", size = 640823, upload-time = "2026-07-10T20:55:45.461Z" }, ] [[package]] From 916067d29ec85954d878d159be18b2e76c1d3374 Mon Sep 17 00:00:00 2001 From: "John M. Kuchta" Date: Wed, 15 Jul 2026 16:30:11 -0700 Subject: [PATCH 06/11] feat: add custom headers and Smart Flow specs Restore the early-access enablement helper and include the current local Claude configuration. --- .claude/settings.local.json | 16 ++ docs/SMARTFLOW.md | 217 +++++++++++++++++++++++ docs/smartflow-vectors.json | 230 +++++++++++++++++++++++++ examples/ci/enable_all_early_access.py | 51 ++++++ meraki/__init__.py | 16 +- meraki/aio/__init__.py | 16 +- meraki/common.py | 23 ++- meraki/config.py | 10 +- meraki/session/base.py | 36 ++-- 9 files changed, 559 insertions(+), 56 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 docs/SMARTFLOW.md create mode 100644 docs/smartflow-vectors.json create mode 100644 examples/ci/enable_all_early_access.py diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..3d0c2ee7 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,16 @@ +{ + "permissions": { + "allow": [ + "Bash(rm -f ~/.claude/hooks/gsd-check-update-worker.js)", + "Read(//c/Users/jkuchta/.claude/hooks/**)" + ] + }, + "enabledMcpjsonServers": [ + "atlassian", + "figma-remote-mcp", + "slack", + "playwright", + "github", + "mcp-server-snowflake" + ] +} diff --git a/docs/SMARTFLOW.md b/docs/SMARTFLOW.md new file mode 100644 index 00000000..ba0797c4 --- /dev/null +++ b/docs/SMARTFLOW.md @@ -0,0 +1,217 @@ +# Smart Flow — Rate Limiter Specification + +Language-agnostic spec for the Meraki proactive rate limiter. The Python +reference implementation is `meraki/smart_flow.py`; this document defines the +*behavior* so any implementation (Python, PowerShell, .NET, …) can be verified +against the same conformance vectors in `smartflow-vectors.json`. + +Goal: prevent 429s before they happen by throttling per-organization request +rates locally, plus a global per-source-IP ceiling, learning which org each +network/device belongs to as traffic flows. + +--- + +## 1. Token bucket + +The primitive. One bucket = one rate limit. + +**State:** `rate` (tokens/sec), `capacity` (max tokens), `tokens` (current, float), +`last` (monotonic timestamp of last refill). + +**Init:** `tokens = capacity`, `last =` monotonic now at creation. +(The async reference lazily sets `last` on the first `acquire`; equivalent to +setting it at creation when no time passes before the first call.) + +**`acquire()`** — the whole algorithm, executed atomically per bucket: + +``` +now = monotonic() +elapsed = now - last +tokens = min(capacity, tokens + elapsed * rate) # refill +last = now +tokens = tokens - 1 # deduct unconditionally +wait = (-tokens / rate) if tokens < 0 else 0 # deficit -> sleep +if wait > 0: sleep(wait) +``` + +Critical properties, all load-bearing for parity: + +- **Deduct unconditionally; tokens may go negative.** The negative value *is* the + reservation. Concurrent callers each compute their own `wait` against the + accumulated deficit instead of colliding on the same instant. Do **not** clamp + tokens at zero. +- **Reserve under lock, sleep outside it.** Compute `wait` while holding the + per-bucket lock, release, then sleep. Serializing the sleeps destroys burst + parallelism. +- **`rate` has a floor of 0.5.** Setting `rate` to anything lower clamps to `0.5` + (prevents AIMD decrease from stalling a bucket to zero throughput). + +--- + +## 2. Rate defaults + +| Bucket | rate | capacity | +| --- | --- | --- | +| Per-org | `10.0` (SDK config default surfaces `9`) | `10` | +| Global (per source IP) | `100.0` | `100` (`int(global_rate)`) | + +Meraki enforces ~10 req/s per org and ~100 req/s per source IP. Per-org default +is set below the ceiling to reserve headroom for other apps. + +--- + +## 3. URL → identifier extraction + +Three regexes, searched (not full-match) against the request URL: + +| Identifier | Pattern | Capture | +| --- | --- | --- | +| org | `/organizations/([^/]+)` | org id | +| network | `/networks/([^/]+)` | network id | +| device | `/devices/([^/]+)` | serial | + +**`resolve_org(url)`** returns the first that resolves: + +1. org id directly from URL → return it +2. else network id from URL → look up `network_to_org[net]` (may be `None`) +3. else serial from URL → look up `serial_to_org[serial]` (may be `None`) +4. else `None` + +--- + +## 4. acquire(url) + +``` +global_bucket.acquire() # always, first +org = resolve_org(url) +if org: + bucket(org).acquire() # get-or-create org bucket +else: + resolve_inline(url) # sync ref; async fires a background task + org = resolve_org(url) + if org: bucket(org).acquire() +``` + +Global bucket is charged on **every** request regardless of org resolution. +An unresolved request pays only the global cost until its org is learned. + +**Sync vs async divergence (the one intentional difference):** +- Sync `resolve_inline` calls the resolver **inline and blocks**, so a freshly + resolved org's bucket is acquired *in the same call*. +- Async `_trigger_background_resolve` fires a one-shot background task and does + **not** block; the org bucket is acquired on *subsequent* calls once learned. + +An implementation without async (e.g. PowerShell sync) follows the sync path. + +--- + +## 5. AIMD rate adaptation + +Additive-increase / multiplicative-decrease on top of the static limits. + +**`on_rate_limited(url)`** (called on a 429): + +``` +org = resolve_org(url) +if org has a bucket: + bucket.rate *= 0.7 # multiplicative decrease +elif url is an "unresolved scoped url": + skip # do NOT penalize global +else: + global_bucket.rate *= 0.7 +``` + +**Unresolved scoped URL** = URL has a network or device component but **no** +explicit `/organizations/`. The offending org is specific but unknown; +penalizing the global bucket would punish every other org for one org's 429, so +skip and let resolution catch up. + +**`on_success(url)`** (called on a 2xx): + +``` +org = resolve_org(url) +if org has a bucket and bucket.rate < configured_org_rate: + bucket.rate = min(configured_org_rate, bucket.rate + 0.2) # additive increase +if global_bucket.rate < configured_global_rate: + global_bucket.rate = min(configured_global_rate, global_bucket.rate + 0.5) +``` + +Increments: **+0.2** per-org, **+0.5** global. Decrease factor: **×0.7** both. +Remember the `0.5` rate floor from §1 bounds the decrease. + +--- + +## 6. Learning org mappings + +**`learn_from_response(url, body)`** — called on successful GET responses to +populate the net→org / serial→org caches. + +Resolve the governing org first: +1. org id from URL (`/organizations/`), else +2. org id from body: `body.organizationId`, else `body.organization.id` +3. if neither → return (nothing learned) + +Then record mappings (only counting ones that *change* an existing value): + +- network id from **URL** → `network_to_org` +- serial from **URL** → `serial_to_org` +- from **body**: `body.networkId`, `body.serial`, `body.network.id` + +Each changed mapping increments a `dirty` counter (see §7). + +Explicit registration API (used by eager hydration / resolver callbacks): +`register_org(org)`, `register_network(net, org)`, `register_device(serial, org)`. + +--- + +## 7. Disk cache + +Persists learned mappings across sessions so warm runs skip re-learning. + +**Format** (`rate_limit_cache.json`, default `~/.meraki/.cache/`): + +```json +{ + "saved_at": "2026-07-08T12:00:00Z", + "networks": [{ "id": "N_1", "organization": { "id": "O_1" } }], + "devices": [{ "serial": "Q2XX-XXXX-XXXX", "organization": { "id": "O_1" } }] +} +``` + +**`saved_at`** is UTC, format `%Y-%m-%dT%H:%M:%SZ` (trailing `Z`, no offset). + +**Load / freshness:** +- No file → start empty. +- TTL default `604800` s (7 days). `None` = never expire. +- Expired if `saved_at` missing, unparseable, or `now - saved_at > ttl` → + ignore file, rebuild. `cache_fresh` stays false. +- On fresh load, populate both maps; set `cache_fresh = true`. +- Malformed JSON / missing keys / IO error → swallow, start empty. + +**Flush cadence:** when `dirty >= 50`, save and reset the counter. Async saves on +a background thread and only subtracts the flushed count on success (unsaved +mappings are retained, not lost, if the write fails). Async `shutdown()` drains +in-flight resolves + pending flush, then does a final save. + +--- + +## 8. Resolver & hydrator callbacks + +Hooks the SDK wires in so the limiter can fill its cache without knowing about +HTTP: + +- **resolver** `(id_type, identifier) -> org_id | None`, `id_type ∈ {"network","device"}`. + Called for an unresolved id. Guarded by a `pending_lookups` set so the same id + isn't resolved twice concurrently. +- **hydrator** `(org_id) -> void`. Called **once per org** (tracked in + `hydrated_orgs`) after first resolution, to bulk-register all of that org's + networks/devices via the register APIs. + +--- + +## Conformance + +`smartflow-vectors.json` encodes deterministic cases for each section above +(bucket math with injected timestamps, URL resolution, AIMD, learning, cache +freshness). An implementation is conformant if it reproduces every vector's +expected output. See that file's `notes` field per case. diff --git a/docs/smartflow-vectors.json b/docs/smartflow-vectors.json new file mode 100644 index 00000000..f2245270 --- /dev/null +++ b/docs/smartflow-vectors.json @@ -0,0 +1,230 @@ +{ + "$comment": "Conformance vectors for the Smart Flow rate limiter. See SMARTFLOW.md. All time is injected (monotonic seconds / epoch seconds) so cases are deterministic; no wall-clock is read. An implementation is conformant if it reproduces every expected output. Floats compared with tolerance 1e-9.", + "version": 1, + + "token_bucket": { + "$comment": "rate in tokens/sec, capacity in tokens. Each step calls acquire() at the given monotonic 'now'. tokens_after and wait are the post-acquire state. See SMARTFLOW.md section 1.", + "cases": [ + { + "name": "single_acquire_full_bucket", + "rate": 10.0, "capacity": 10.0, "init_tokens": 10.0, "init_last": 0.0, + "steps": [ + { "now": 0.0, "tokens_after": 9.0, "wait": 0.0 } + ], + "notes": "elapsed 0, no refill, deduct 1 from full bucket, no wait." + }, + { + "name": "burst_beyond_capacity_goes_negative", + "rate": 10.0, "capacity": 10.0, "init_tokens": 10.0, "init_last": 0.0, + "steps": [ + { "now": 0.0, "tokens_after": 9.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 8.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 7.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 6.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 5.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 4.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 3.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 2.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 1.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": 0.0, "wait": 0.0 }, + { "now": 0.0, "tokens_after": -1.0, "wait": 0.1 }, + { "now": 0.0, "tokens_after": -2.0, "wait": 0.2 }, + { "now": 0.0, "tokens_after": -3.0, "wait": 0.3 }, + { "now": 0.0, "tokens_after": -4.0, "wait": 0.4 }, + { "now": 0.0, "tokens_after": -5.0, "wait": 0.5 } + ], + "notes": "Deduct unconditionally; deficit is the reservation. 11th call waits 0.1s, each subsequent +0.1s. Do NOT clamp at zero." + }, + { + "name": "refill_after_elapsed_time", + "rate": 10.0, "capacity": 10.0, "init_tokens": -5.0, "init_last": 0.0, + "steps": [ + { "now": 1.0, "tokens_after": 4.0, "wait": 0.0 } + ], + "notes": "1s elapsed refills 1*10=10 tokens: -5+10=5, capped at capacity 10 (not exceeded here), deduct 1 -> 4." + }, + { + "name": "refill_clamped_to_capacity", + "rate": 10.0, "capacity": 10.0, "init_tokens": 5.0, "init_last": 0.0, + "steps": [ + { "now": 100.0, "tokens_after": 9.0, "wait": 0.0 } + ], + "notes": "Huge elapsed would add 1000 tokens but refill is min(capacity, ...) = 10, then deduct 1 -> 9." + }, + { + "name": "global_bucket_defaults", + "rate": 100.0, "capacity": 100.0, "init_tokens": 100.0, "init_last": 0.0, + "steps": [ + { "now": 0.0, "tokens_after": 99.0, "wait": 0.0 } + ], + "notes": "Global per-source-IP bucket: rate 100, capacity int(100)=100." + } + ] + }, + + "rate_setter_floor": { + "$comment": "Setting rate clamps to a floor of 0.5. SMARTFLOW.md section 1.", + "cases": [ + { "name": "above_floor", "set_rate": 3.0, "expected_rate": 3.0 }, + { "name": "at_floor", "set_rate": 0.5, "expected_rate": 0.5 }, + { "name": "below_floor", "set_rate": 0.2, "expected_rate": 0.5 }, + { "name": "zero_clamped", "set_rate": 0.0, "expected_rate": 0.5 } + ] + }, + + "resolve_org": { + "$comment": "resolve_org(url) given a cache of network_to_org / serial_to_org. SMARTFLOW.md section 3.", + "network_to_org": { "N_1": "O_2" }, + "serial_to_org": { "Q2XX-XXXX-XXXX": "O_3" }, + "cases": [ + { "name": "explicit_org", "url": "/organizations/O_1/networks", "expected_org": "O_1" }, + { "name": "network_cached", "url": "/networks/N_1/clients", "expected_org": "O_2" }, + { "name": "network_uncached", "url": "/networks/N_9/clients", "expected_org": null }, + { "name": "device_cached", "url": "/devices/Q2XX-XXXX-XXXX/lldpCdp", "expected_org": "O_3" }, + { "name": "device_uncached", "url": "/devices/Q2ZZ-ZZZZ-ZZZZ/clients", "expected_org": null }, + { "name": "org_precedence_over_net", "url": "/organizations/O_1/networks/N_1", "expected_org": "O_1" }, + { "name": "no_identifier", "url": "/administered/identities/me", "expected_org": null } + ] + }, + + "is_unresolved_scoped_url": { + "$comment": "Purely URL-structural: true if a network/device component is present AND no explicit /organizations/. Independent of cache. SMARTFLOW.md section 5.", + "cases": [ + { "name": "org_url", "url": "/organizations/O_1/networks", "expected": false }, + { "name": "org_and_network", "url": "/organizations/O_1/networks/N_1", "expected": false }, + { "name": "network_only", "url": "/networks/N_9/clients", "expected": true }, + { "name": "device_only", "url": "/devices/Q2ZZ-ZZZZ-ZZZZ/clients", "expected": true }, + { "name": "no_scope", "url": "/administered/identities/me", "expected": false } + ] + }, + + "aimd": { + "$comment": "on_rate_limited multiplies rate by 0.7; on_success adds 0.2 (org) / 0.5 (global) capped at configured rate. Rate floor 0.5 applies via setter. SMARTFLOW.md section 5.", + "cases": [ + { + "name": "org_decrease", + "op": "on_rate_limited", "target": "org", "start_rate": 10.0, "expected_rate": 7.0, + "notes": "10 * 0.7 = 7.0" + }, + { + "name": "org_increase_below_cap", + "op": "on_success", "target": "org", "configured_rate": 10.0, "start_rate": 7.0, "expected_rate": 7.2, + "notes": "min(10, 7 + 0.2) = 7.2" + }, + { + "name": "org_increase_hits_cap", + "op": "on_success", "target": "org", "configured_rate": 10.0, "start_rate": 9.95, "expected_rate": 10.0, + "notes": "min(10, 9.95 + 0.2) = 10.0 (clamped)" + }, + { + "name": "org_increase_noop_at_cap", + "op": "on_success", "target": "org", "configured_rate": 10.0, "start_rate": 10.0, "expected_rate": 10.0, + "notes": "rate not < configured, no change" + }, + { + "name": "global_decrease", + "op": "on_rate_limited", "target": "global", "start_rate": 100.0, "expected_rate": 70.0, + "notes": "resolves to no known org and not an unresolved-scoped url -> global penalized. 100 * 0.7 = 70." + }, + { + "name": "global_increase_below_cap", + "op": "on_success", "target": "global", "configured_rate": 100.0, "start_rate": 70.0, "expected_rate": 70.5, + "notes": "min(100, 70 + 0.5) = 70.5" + }, + { + "name": "decrease_respects_floor", + "op": "on_rate_limited", "target": "org", "start_rate": 0.6, "expected_rate": 0.5, + "notes": "0.6 * 0.7 = 0.42, clamped up to floor 0.5 by the rate setter." + }, + { + "name": "rate_limited_unresolved_scoped_skips_global", + "op": "on_rate_limited", "target": "global", "url": "/networks/N_9/clients", + "org_resolvable": false, "start_rate": 100.0, "expected_rate": 100.0, + "notes": "Unresolved network/device url: org unknown but specific; global bucket must NOT be penalized. No change." + } + ] + }, + + "learn_from_response": { + "$comment": "Given url + body, which mappings change. org resolved from url first, else body.organizationId, else body.organization.id. Only changed mappings count. SMARTFLOW.md section 6.", + "cases": [ + { + "name": "org_and_network_from_url", + "url": "/organizations/O_1/networks/N_1", "body": {}, + "expected_network_to_org": { "N_1": "O_1" }, "expected_serial_to_org": {}, + "changed_networks": 1, "changed_devices": 0 + }, + { + "name": "org_and_device_from_url", + "url": "/organizations/O_1/devices/Q2AA-AAAA-AAAA", "body": {}, + "expected_network_to_org": {}, "expected_serial_to_org": { "Q2AA-AAAA-AAAA": "O_1" }, + "changed_networks": 0, "changed_devices": 1 + }, + { + "name": "org_from_body_organizationId", + "url": "/networks/N_1/clients", "body": { "organizationId": "O_5" }, + "expected_network_to_org": { "N_1": "O_5" }, "expected_serial_to_org": {}, + "changed_networks": 1, "changed_devices": 0 + }, + { + "name": "org_from_body_organization_id", + "url": "/networks/N_2/clients", "body": { "organization": { "id": "O_6" } }, + "expected_network_to_org": { "N_2": "O_6" }, "expected_serial_to_org": {}, + "changed_networks": 1, "changed_devices": 0 + }, + { + "name": "nested_network_id_from_body", + "url": "/organizations/O_1/somethingElse", "body": { "network": { "id": "N_3" } }, + "expected_network_to_org": { "N_3": "O_1" }, "expected_serial_to_org": {}, + "changed_networks": 1, "changed_devices": 0 + }, + { + "name": "body_serial_and_networkId", + "url": "/organizations/O_1/x", "body": { "networkId": "N_4", "serial": "Q2BB-BBBB-BBBB" }, + "expected_network_to_org": { "N_4": "O_1" }, "expected_serial_to_org": { "Q2BB-BBBB-BBBB": "O_1" }, + "changed_networks": 1, "changed_devices": 1 + }, + { + "name": "no_org_anywhere_noop", + "url": "/administered/identities/me", "body": {}, + "expected_network_to_org": {}, "expected_serial_to_org": {}, + "changed_networks": 0, "changed_devices": 0 + }, + { + "name": "unchanged_mapping_not_counted", + "url": "/organizations/O_1/networks/N_1", "body": {}, + "preexisting_network_to_org": { "N_1": "O_1" }, + "expected_network_to_org": { "N_1": "O_1" }, "expected_serial_to_org": {}, + "changed_networks": 0, "changed_devices": 0, + "notes": "Mapping already equals O_1, so no change is counted (dirty not incremented)." + } + ] + }, + + "cache_freshness": { + "$comment": "Load-time freshness decision. now and saved_ts are epoch seconds (injected). ttl in seconds; null = never expire. SMARTFLOW.md section 7.", + "cases": [ + { "name": "fresh_within_ttl", "now": 1000000.0, "saved_ts": 999000.0, "ttl": 604800.0, "expected_fresh": true, + "notes": "age 1000s < ttl -> load, cache_fresh true." }, + { "name": "expired_past_ttl", "now": 2000000.0, "saved_ts": 1000000.0, "ttl": 604800.0, "expected_fresh": false, + "notes": "age 1,000,000s > 604800 -> ignore file, rebuild." }, + { "name": "saved_at_missing", "now": 1000000.0, "saved_ts": null, "ttl": 604800.0, "expected_fresh": false, + "notes": "No/unparseable saved_at -> expired." }, + { "name": "ttl_none_never_expires", "now": 9999999999.0, "saved_ts": 1.0, "ttl": null, "expected_fresh": true, + "notes": "ttl None disables expiry regardless of age." }, + { "name": "exactly_at_ttl_boundary", "now": 604800.0, "saved_ts": 0.0, "ttl": 604800.0, "expected_fresh": true, + "notes": "age == ttl is NOT > ttl, so still fresh (boundary inclusive)." } + ] + }, + + "saved_at_format": { + "$comment": "saved_at is UTC strftime %Y-%m-%dT%H:%M:%SZ. Parser returns epoch seconds or null. SMARTFLOW.md section 7.", + "cases": [ + { "name": "valid", "value": "2026-07-08T12:00:00Z", "expected_epoch": 1783512000.0 }, + { "name": "missing_z", "value": "2026-07-08T12:00:00", "expected_epoch": null }, + { "name": "with_offset", "value": "2026-07-08T12:00:00+00:00", "expected_epoch": null }, + { "name": "not_a_string", "value": 12345, "expected_epoch": null }, + { "name": "garbage", "value": "not-a-date", "expected_epoch": null } + ] + } +} diff --git a/examples/ci/enable_all_early_access.py b/examples/ci/enable_all_early_access.py new file mode 100644 index 00000000..19a7b5ed --- /dev/null +++ b/examples/ci/enable_all_early_access.py @@ -0,0 +1,51 @@ +"""Opt in to all available early access features for Meraki organizations. + +Reads EA_ORG_0 through EA_ORG_7 from the environment, and for each org +fetches the feature list, creates org-wide opt-ins for any features not +already enabled, and prints a summary report. + +WARNING: This will subject the organizations to unannounced breaking API +changes. +""" + +import asyncio +import os +import sys + +import meraki.aio + +ORG_IDS: list[str] = [v for i in range(8) if (v := os.environ.get(f"EA_ORG_{i}", ""))] +if not ORG_IDS: + sys.exit("No EA_ORG_* environment variables are set") + + +async def enable_early_access(dashboard, org_id: str): + features = await dashboard.organizations.getOrganizationEarlyAccessFeatures(org_id) + opt_ins = await dashboard.organizations.getOrganizationEarlyAccessFeaturesOptIns(org_id) + + opted_in_short_names = {oi["shortName"] for oi in opt_ins} + + tasks = [] + for feature in features: + if feature["shortName"] not in opted_in_short_names: + tasks.append(dashboard.organizations.createOrganizationEarlyAccessFeaturesOptIn(org_id, feature["shortName"])) + + new_opt_ins = await asyncio.gather(*tasks) if tasks else [] + + all_opt_ins = opt_ins + list(new_opt_ins) + print(f"\nOrg {org_id}: enabled {len(new_opt_ins)} new features ({len(opt_ins)} already opted in)") + print(f" All early access features ({len(all_opt_ins)} total):") + for oi in all_opt_ins: + print(f" - {oi['shortName']}") + + return all_opt_ins + + +async def main(): + async with meraki.aio.AsyncDashboardAPI(suppress_logging=True) as dashboard: + results = await asyncio.gather(*(enable_early_access(dashboard, org_id) for org_id in ORG_IDS)) + return results + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/meraki/__init__.py b/meraki/__init__.py index dbd324d9..114dcfe0 100644 --- a/meraki/__init__.py +++ b/meraki/__init__.py @@ -24,8 +24,7 @@ # Config import from meraki.config import ( API_KEY_ENVIRONMENT_VARIABLE, - MERAKI_APP_ID, - MERAKI_APP_BEARER_TOKEN, + CUSTOM_HEADERS, DEFAULT_BASE_URL, SINGLE_REQUEST_TIMEOUT, CERTIFICATE_PATH, @@ -77,8 +76,7 @@ class DashboardAPI(object): **Creates a persistent Meraki dashboard API session** - api_key (string): API key generated in dashboard; can also be set as an environment variable MERAKI_DASHBOARD_API_KEY - - meraki_app_id (string): optional Meraki app ID; can also be set as an environment variable MERAKI_APP_ID - - meraki_app_bearer_token (string): optional Meraki app bearer token; can also be set as an environment variable MERAKI_APP_BEARER_TOKEN + - custom_headers (dict): optional extra HTTP headers appended to every request; SDK-managed headers (Authorization, Content-Type, User-Agent) take precedence on collision - base_url (string): preceding all endpoint resources - single_request_timeout (integer): maximum number of seconds for each API call - certificate_path (string): path for TLS/SSL certificate verification if behind local proxy @@ -111,8 +109,7 @@ class DashboardAPI(object): def __init__( self, api_key=None, - meraki_app_id=MERAKI_APP_ID, - meraki_app_bearer_token=MERAKI_APP_BEARER_TOKEN, + custom_headers=CUSTOM_HEADERS, base_url=DEFAULT_BASE_URL, single_request_timeout=SINGLE_REQUEST_TIMEOUT, certificate_path=CERTIFICATE_PATH, @@ -148,10 +145,6 @@ def __init__( if not api_key: raise APIKeyError() - # Pull the Meraki app ID and bearer token from environment variables if present - meraki_app_id = meraki_app_id or os.environ.get("MERAKI_APP_ID") - meraki_app_bearer_token = meraki_app_bearer_token or os.environ.get("MERAKI_APP_BEARER_TOKEN") - # Pull the BE GEO ID from an environment variable if present be_geo_id = be_geo_id or os.environ.get("BE_GEO_ID") @@ -193,8 +186,7 @@ def __init__( self._session = RestSession( logger=self._logger, api_key=api_key, - meraki_app_id=meraki_app_id, - meraki_app_bearer_token=meraki_app_bearer_token, + custom_headers=custom_headers, base_url=base_url, single_request_timeout=single_request_timeout, certificate_path=certificate_path, diff --git a/meraki/aio/__init__.py b/meraki/aio/__init__.py index 17b61d2a..3ac462b6 100644 --- a/meraki/aio/__init__.py +++ b/meraki/aio/__init__.py @@ -27,8 +27,7 @@ # Config import from meraki.config import ( API_KEY_ENVIRONMENT_VARIABLE, - MERAKI_APP_ID, - MERAKI_APP_BEARER_TOKEN, + CUSTOM_HEADERS, DEFAULT_BASE_URL, SINGLE_REQUEST_TIMEOUT, CERTIFICATE_PATH, @@ -67,8 +66,7 @@ class AsyncDashboardAPI: **Creates a persistent Meraki dashboard API session** - api_key (string): API key generated in dashboard; can also be set as an environment variable MERAKI_DASHBOARD_API_KEY - - meraki_app_id (string): optional Meraki app ID; can also be set as an environment variable MERAKI_APP_ID - - meraki_app_bearer_token (string): optional Meraki app bearer token; can also be set as an environment variable MERAKI_APP_BEARER_TOKEN + - custom_headers (dict): optional extra HTTP headers appended to every request; SDK-managed headers (Authorization, Content-Type, User-Agent) take precedence on collision - base_url (string): preceding all endpoint resources - single_request_timeout (integer): maximum number of seconds for each API call - certificate_path (string): path for TLS/SSL certificate verification if behind local proxy @@ -102,8 +100,7 @@ class AsyncDashboardAPI: def __init__( self, api_key=None, - meraki_app_id=MERAKI_APP_ID, - meraki_app_bearer_token=MERAKI_APP_BEARER_TOKEN, + custom_headers=CUSTOM_HEADERS, base_url=DEFAULT_BASE_URL, single_request_timeout=SINGLE_REQUEST_TIMEOUT, certificate_path=CERTIFICATE_PATH, @@ -140,10 +137,6 @@ def __init__( if not api_key: raise APIKeyError() - # Pull the Meraki app ID and bearer token from environment variables if present - meraki_app_id = meraki_app_id or os.environ.get("MERAKI_APP_ID") - meraki_app_bearer_token = meraki_app_bearer_token or os.environ.get("MERAKI_APP_BEARER_TOKEN") - # Pull the BE GEO ID from an environment variable if present be_geo_id = be_geo_id or os.environ.get("BE_GEO_ID") @@ -185,8 +178,7 @@ def __init__( self._session = AsyncRestSession( logger=self._logger, api_key=api_key, - meraki_app_id=meraki_app_id, - meraki_app_bearer_token=meraki_app_bearer_token, + custom_headers=custom_headers, base_url=base_url, single_request_timeout=single_request_timeout, certificate_path=certificate_path, diff --git a/meraki/common.py b/meraki/common.py index 207ea5f3..5fbe1033 100644 --- a/meraki/common.py +++ b/meraki/common.py @@ -51,15 +51,26 @@ def validate_user_agent(be_geo_id, caller): return caller_string -def validate_meraki_app_value(argument, value): - # Meraki app ID / bearer token must fit within a 127-character header value - if value and len(str(value)) > 127: +def validate_custom_headers(custom_headers): + # Custom headers must be a dict of str -> str + if not custom_headers: + return {} + if not isinstance(custom_headers, dict): raise SessionInputError( - argument, - value, - f"{argument} must be 127 characters or fewer (got {len(str(value))}).", + "custom_headers", + custom_headers, + "custom_headers must be a dict of header name -> value.", None, ) + for name, value in custom_headers.items(): + if not isinstance(name, str) or not isinstance(value, str): + raise SessionInputError( + "custom_headers", + {name: value}, + "custom_headers keys and values must both be strings.", + None, + ) + return dict(custom_headers) def reject_v0_base_url(self): diff --git a/meraki/config.py b/meraki/config.py index 3bf90ad6..00534f29 100644 --- a/meraki/config.py +++ b/meraki/config.py @@ -9,12 +9,10 @@ # Meraki dashboard API key, set either at instantiation or as an environment variable API_KEY_ENVIRONMENT_VARIABLE = "MERAKI_DASHBOARD_API_KEY" -# --- Meraki App --- -# Meraki app ID, set either at instantiation or as an environment variable -MERAKI_APP_ID = "" - -# Meraki app bearer token, set either at instantiation or as an environment variable -MERAKI_APP_BEARER_TOKEN = "" +# --- Custom Headers --- +# Extra HTTP headers appended to every request, e.g. {"X-MyApp": "id", "X-Trace": "abc"}. +# Additive only: SDK-managed headers (Authorization, Content-Type, User-Agent) always win on collision. +CUSTOM_HEADERS = {} # --- Base URL --- # Base URL preceding all endpoint resources diff --git a/meraki/session/base.py b/meraki/session/base.py index d4d5249b..51a786bd 100644 --- a/meraki/session/base.py +++ b/meraki/session/base.py @@ -12,17 +12,16 @@ check_python_version, reject_v0_base_url, validate_base_url, - validate_meraki_app_value, + validate_custom_headers, validate_user_agent, ) from meraki.config import ( ACTION_BATCH_RETRY_WAIT_TIME, BE_GEO_ID, CERTIFICATE_PATH, + CUSTOM_HEADERS, DEFAULT_BASE_URL, MAXIMUM_RETRIES, - MERAKI_APP_BEARER_TOKEN, - MERAKI_APP_ID, MERAKI_PYTHON_SDK_CALLER, NETWORK_DELETE_RETRY_WAIT_TIME, NGINX_429_RETRY_WAIT_TIME, @@ -98,8 +97,7 @@ def __init__( self, logger: Any, api_key: str, - meraki_app_id: str = MERAKI_APP_ID, - meraki_app_bearer_token: str = MERAKI_APP_BEARER_TOKEN, + custom_headers: Optional[Dict[str, str]] = None, base_url: str = DEFAULT_BASE_URL, single_request_timeout: int = SINGLE_REQUEST_TIMEOUT, certificate_path: str = CERTIFICATE_PATH, @@ -129,10 +127,7 @@ def __init__( # Store config attributes self._version = __version__ self._api_key = str(api_key) - validate_meraki_app_value("meraki_app_id", meraki_app_id) - validate_meraki_app_value("meraki_app_bearer_token", meraki_app_bearer_token) - self._meraki_app_id = meraki_app_id - self._meraki_app_bearer_token = meraki_app_bearer_token + self._custom_headers = validate_custom_headers(custom_headers if custom_headers is not None else CUSTOM_HEADERS) self._base_url = str(base_url) self._single_request_timeout = single_request_timeout self._certificate_path = certificate_path @@ -167,8 +162,9 @@ def __init__( self._logger = logger self._parameters: Dict[str, Any] = {"version": self._version} self._parameters["api_key"] = "*" * 36 + self._api_key[-4:] - if self._meraki_app_bearer_token: - self._parameters["meraki_app_bearer_token"] = "*" * 36 + str(self._meraki_app_bearer_token)[-4:] + if self._custom_headers: + # Log header names only; values may carry secrets. + self._parameters["custom_headers"] = sorted(self._custom_headers.keys()) self._parameters["base_url"] = self._base_url self._parameters["single_request_timeout"] = self._single_request_timeout self._parameters["certificate_path"] = self._certificate_path @@ -501,13 +497,13 @@ def _is_action_batch_concurrency(self, message: Any) -> bool: def _build_headers(self) -> Dict[str, str]: """Build standard request headers.""" - headers = { - "Authorization": "Bearer " + self._api_key, - "Content-Type": "application/json", - "User-Agent": f"python-meraki/{self._version} " + validate_user_agent(self._be_geo_id, self._caller), - } - if self._meraki_app_id: - headers["X-MerakiApp"] = self._meraki_app_id - if self._meraki_app_bearer_token: - headers["X-MerakiApp-Authorization"] = "Bearer " + self._meraki_app_bearer_token + # Custom headers first so SDK-managed headers win on collision (additive only). + headers = dict(self._custom_headers) + headers.update( + { + "Authorization": "Bearer " + self._api_key, + "Content-Type": "application/json", + "User-Agent": f"python-meraki/{self._version} " + validate_user_agent(self._be_geo_id, self._caller), + } + ) return headers From 008182d01da25b893999c2aa6220ce09579e66d6 Mon Sep 17 00:00:00 2001 From: "John M. Kuchta" Date: Wed, 15 Jul 2026 17:01:40 -0700 Subject: [PATCH 07/11] docs: design write query parameter support --- ...026-07-15-write-query-parameters-design.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-15-write-query-parameters-design.md diff --git a/docs/superpowers/specs/2026-07-15-write-query-parameters-design.md b/docs/superpowers/specs/2026-07-15-write-query-parameters-design.md new file mode 100644 index 00000000..f29b5f9d --- /dev/null +++ b/docs/superpowers/specs/2026-07-15-write-query-parameters-design.md @@ -0,0 +1,21 @@ +# Write-operation query parameters + +## Problem + +The generator documents query parameters on POST, PUT, and PATCH operations but only serializes request-body parameters. Those query parameters are silently dropped. Action-batch methods have the same omission because their action resource never receives a query string. + +## Design + +- Collect query parameters for every generated HTTP method. +- Pass both `params` and `json` through synchronous and asynchronous POST, PUT, and PATCH session helpers. +- For action batches, append encoded query parameters to the action `resource`, because the action format has no separate query-parameter field. +- Keep existing GET and DELETE behavior unchanged. +- Keep keyword validation aware of both query and body parameters. + +## Test + +Add one hermetic generator regression test using a synthetic POST operation with a boolean query parameter and a JSON body property. The test will verify that standard and asynchronous generated clients pass both `params` and `payload`, and that the batch client includes the encoded query parameter in its resource. + +## Scope + +No endpoint-specific exceptions, generated API regeneration, new dependency, or unrelated refactoring is included. From 36dee446dbd671fd17e9e68c09b327a282f3547d Mon Sep 17 00:00:00 2001 From: "John M. Kuchta" Date: Wed, 15 Jul 2026 17:08:21 -0700 Subject: [PATCH 08/11] docs: plan write query parameter support --- .../2026-07-15-write-query-parameters.md | 218 ++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-15-write-query-parameters.md diff --git a/docs/superpowers/plans/2026-07-15-write-query-parameters.md b/docs/superpowers/plans/2026-07-15-write-query-parameters.md new file mode 100644 index 00000000..ef79be22 --- /dev/null +++ b/docs/superpowers/plans/2026-07-15-write-query-parameters.md @@ -0,0 +1,218 @@ +# Write-operation Query Parameters Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Preserve OpenAPI query parameters on generated POST, PUT, and PATCH methods, including action-batch methods. + +**Architecture:** The generator will collect query parameters independently of the HTTP method. Standard and asynchronous methods will pass them through trailing-compatible session helper arguments; batch methods will encode them into the action resource with the already-installed `httpx` dependency. + +**Tech Stack:** Python 3.11+, Jinja2, httpx, pytest + +## Global Constraints + +- Add exactly one regression test. +- Cover standard, asynchronous, and action-batch generation. +- Do not add endpoint-specific exceptions or regenerate generated API modules. +- Do not add a dependency or perform unrelated refactoring. + +--- + +### Task 1: Generate and transport query parameters on write operations + +**Files:** +- Modify: `tests/generator/test_generator_audit.py` +- Modify: `generator/generate_library.py` +- Modify: `generator/batch_function_template.jinja2` +- Modify: `generator/batch_class_template.jinja2` +- Modify: `meraki/session/sync.py` +- Modify: `meraki/session/async_.py` + +**Interfaces:** +- Consumes: OpenAPI parameters where `in == "query"`, existing Jinja templates, and existing `SessionBase.request(..., **kwargs)` support for `params`. +- Produces: `RestSession.post/put/patch(metadata, url, json=None, params=None)`, matching async signatures, generated write calls using `params=params`, and batch action resources containing the encoded query string. + +- [ ] **Step 1: Add the single failing regression test** + +Append this synthetic spec and test before the module's `if __name__ == "__main__"` block in `tests/generator/test_generator_audit.py`: + +```python +def _write_query_spec(): + return { + "paths": { + "/things": { + "post": { + "operationId": "claimThings", + "tags": ["organizations"], + "summary": "Claim things", + "parameters": [ + { + "name": "validate", + "in": "query", + "required": False, + "schema": {"type": "boolean"}, + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["name"], + "properties": { + "name": {"type": "string", "description": "Thing name"} + }, + } + } + } + }, + } + } + } + } + + +def test_write_operations_generate_query_params_for_all_clients(): + clear_cache() + spec = _write_query_spec() + section = {"/things": {"post": spec["paths"]["/things"]["post"]}} + output = io.StringIO() + async_output = io.StringIO() + batch_output = io.StringIO() + + generate_library.generate_standard_and_async_functions( + _jinja_env(), TEMPLATE_DIR, section, output, async_output, spec + ) + generate_library.generate_action_batch_functions( + _jinja_env(), + TEMPLATE_DIR, + section, + batch_output, + [{"summary": "Claim things", "operation": "create"}], + spec, + ) + + for rendered in (output.getvalue(), async_output.getvalue()): + assert 'query_params = ["validate", ]' in rendered + assert "self._session.post(metadata, resource, payload, params=params)" in rendered + + batch_rendered = batch_output.getvalue() + assert 'query_params = ["validate", ]' in batch_rendered + assert 'resource += f"?{httpx.QueryParams(params)}"' in batch_rendered +``` + +- [ ] **Step 2: Run the regression test and verify RED** + +Run: + +```powershell +uv run pytest tests/generator/test_generator_audit.py::test_write_operations_generate_query_params_for_all_clients -q +``` + +Expected: FAIL because generated POST methods do not define query parameters or pass `params`, and batch resources do not contain a query string. + +- [ ] **Step 3: Collect query parameters for all generated methods** + +In `generate_standard_and_async_functions`, initialize query parameters before method dispatch and restrict array handling to query arrays: + +```python +query_params = return_params(operation, all_params, ["query"]) +array_params = {k: v for k, v in query_params.items() if v["type"] == "array"} +body_params = path_params = {} +``` + +Leave each method branch responsible only for `body_params` and `path_params`. For POST, PUT, and PATCH, build the call without changing body-only output: + +```python +args = "metadata, resource" +if body_params: + args += ", payload" +if query_params: + args += ", params=params" +call_line = f"return self._session.{method}({args})" +``` + +Apply the same query and query-array initialization in `generate_action_batch_functions` before its method-specific body handling. + +- [ ] **Step 4: Encode batch query parameters in the resource** + +Add the existing runtime dependency to `generator/batch_class_template.jinja2`: + +```python +import urllib + +import httpx +``` + +After query-array normalization in `generator/batch_function_template.jinja2`, append query parameters to the batch resource: + +```jinja2 +{% if query_params|length > 0 %} +resource += f"?{httpx.QueryParams(params)}" + +{% endif %} +``` + +- [ ] **Step 5: Pass query parameters through synchronous session helpers** + +Change POST, PUT, and PATCH in `meraki/session/sync.py` without breaking existing positional JSON callers: + +```python +def post(self, metadata, url, json=None, params=None): + metadata["method"] = "POST" + metadata["url"] = url + metadata["params"] = params + metadata["json"] = json + response = self.request(metadata, "POST", url, params=params, json=json) +``` + +Apply the same trailing `params=None`, metadata assignment, and request keyword to `put` and `patch`. + +- [ ] **Step 6: Pass query parameters through asynchronous session helpers** + +Make the equivalent changes in `meraki/session/async_.py`: + +```python +async def post(self, metadata, url, json=None, params=None): + metadata["method"] = "POST" + metadata["url"] = url + metadata["params"] = params + metadata["json"] = json + response = await self.request(metadata, "POST", url, params=params, json=json) +``` + +Apply the same trailing argument and propagation to async `put` and `patch`. + +- [ ] **Step 7: Run focused tests and verify GREEN** + +Run: + +```powershell +uv run pytest tests/generator/test_generator_audit.py tests/unit/test_rest_session.py tests/unit/test_aio_rest_session.py -q +``` + +Expected: all tests pass. + +- [ ] **Step 8: Run formatting and the full test suite** + +Run: + +```powershell +uv run ruff format --check generator meraki tests +uv run ruff check generator meraki tests +uv run pytest -q +``` + +Expected: all commands exit 0 with no formatting, lint, or test failures. + +- [ ] **Step 9: Review and commit** + +Run: + +```powershell +git diff --check +git diff --stat +git add generator/generate_library.py generator/batch_function_template.jinja2 generator/batch_class_template.jinja2 meraki/session/sync.py meraki/session/async_.py tests/generator/test_generator_audit.py docs/superpowers/plans/2026-07-15-write-query-parameters.md +git commit -m "fix: preserve query params on write operations" +``` + +Expected: one implementation commit containing the generator, runtime transport, regression test, and plan. From 393d24c31bdee9d14c466e7a5fe2d4e00b3b19fc Mon Sep 17 00:00:00 2001 From: "John M. Kuchta" Date: Wed, 15 Jul 2026 17:16:52 -0700 Subject: [PATCH 09/11] fix: preserve query params on write operations --- generator/batch_class_template.jinja2 | 2 + generator/batch_function_template.jinja2 | 4 ++ generator/generate_library.py | 26 +++++----- meraki/session/async_.py | 15 +++--- meraki/session/sync.py | 15 +++--- tests/generator/test_generator_audit.py | 60 ++++++++++++++++++++++++ 6 files changed, 99 insertions(+), 23 deletions(-) diff --git a/generator/batch_class_template.jinja2 b/generator/batch_class_template.jinja2 index 7b122abb..e60c320d 100644 --- a/generator/batch_class_template.jinja2 +++ b/generator/batch_class_template.jinja2 @@ -1,5 +1,7 @@ import urllib +import httpx + class ActionBatch{{ class_name }}(object): def __init__(self): diff --git a/generator/batch_function_template.jinja2 b/generator/batch_function_template.jinja2 index 3a30a25a..334ff656 100644 --- a/generator/batch_function_template.jinja2 +++ b/generator/batch_function_template.jinja2 @@ -44,6 +44,10 @@ params[f"{k.strip()}[]"] = kwargs[f"{k}"] params.pop(k.strip()) + {% endif %} + {% if query_params|length > 0 %} + resource += f"?{httpx.QueryParams(params)}" + {% endif %} {% if body_params|length > 0 and batch_operation != 'destroy' %} body_params = [{% for param in body_params %}"{{ param }}", {% endfor %}] diff --git a/generator/generate_library.py b/generator/generate_library.py index d69f0d86..f210a446 100644 --- a/generator/generate_library.py +++ b/generator/generate_library.py @@ -399,11 +399,12 @@ def generate_standard_and_async_functions( # method slips through without setting it (rather than raising NameError). call_line = None + query_params = return_params(operation, all_params, ["query"]) + array_params = {k: v for k, v in query_params.items() if v["type"] == "array"} + body_params = path_params = {} + # Function body for GET endpoints - query_params = array_params = body_params = path_params = {} if method == "get": - query_params = return_params(operation, all_params, ["query"]) - array_params = return_params(operation, all_params, ["array"]) path_params = return_params(operation, all_params, ["path"]) # Function body for POST/PUT/PATCH endpoints @@ -413,7 +414,6 @@ def generate_standard_and_async_functions( # Function body for DELETE endpoints elif method == "delete": - query_params = return_params(operation, all_params, ["query"]) path_params = return_params(operation, all_params, ["path"]) # Add **kwargs if optional params OR body/query/array params exist (templates use kwargs.items()) @@ -455,10 +455,12 @@ def generate_standard_and_async_functions( call_line = "return self._session.get(metadata, resource)" elif method == "post" or method == "put" or method == "patch": + args = "metadata, resource" if body_params: - call_line = f"return self._session.{method}(metadata, resource, payload)" - else: - call_line = f"return self._session.{method}(metadata, resource)" + args += ", payload" + if query_params: + args += ", params=params" + call_line = f"return self._session.{method}({args})" elif method == "delete": if query_params: @@ -568,7 +570,9 @@ def generate_action_batch_functions( all_params, metadata = parse_params_v3(endpoint, path_item, spec) # Initialize param collections - query_params = array_params = body_params = {} + query_params = return_params(operation, all_params, ["query"]) + array_params = {k: v for k, v in query_params.items() if v["type"] == "array"} + body_params = {} path_params = return_params(operation, all_params, ["path"]) # Ensure all URL-referenced params get quote lines in the template @@ -652,8 +656,8 @@ def generate_action_batch_functions( if method == "post" or method == "put": body_params = return_params(operation, all_params, ["body"]) - # Add **kwargs if optional params OR body params exist (batch template uses kwargs.items()) - if return_params(operation, all_params, ["optional"]) or body_params: + # Add **kwargs if optional params OR body/query/array params exist (batch template uses kwargs.items()) + if return_params(operation, all_params, ["optional"]) or body_params or query_params or array_params: definition += ", **kwargs" # Docstring @@ -666,7 +670,7 @@ def generate_action_batch_functions( kwarg_line = "" if return_params(operation, all_params, ["optional"]): kwarg_line = "kwargs.update(locals())" - elif return_params(operation, all_params, ["body"]): + elif return_params(operation, all_params, ["query", "array", "body"]): kwarg_line = "kwargs = locals()" # Assert valid values for enum diff --git a/meraki/session/async_.py b/meraki/session/async_.py index 652760be..750a957a 100644 --- a/meraki/session/async_.py +++ b/meraki/session/async_.py @@ -641,31 +641,34 @@ async def _get_pages_legacy( return results - async def post(self, metadata, url, json=None): + async def post(self, metadata, url, json=None, params=None): metadata["method"] = "POST" metadata["url"] = url + metadata["params"] = params metadata["json"] = json - response = await self.request(metadata, "POST", url, json=json) + response = await self.request(metadata, "POST", url, params=params, json=json) if response: if response.content.strip(): return response.json() return None - async def put(self, metadata, url, json=None): + async def put(self, metadata, url, json=None, params=None): metadata["method"] = "PUT" metadata["url"] = url + metadata["params"] = params metadata["json"] = json - response = await self.request(metadata, "PUT", url, json=json) + response = await self.request(metadata, "PUT", url, params=params, json=json) if response: if response.content.strip(): return response.json() return None - async def patch(self, metadata, url, json=None): + async def patch(self, metadata, url, json=None, params=None): metadata["method"] = "PATCH" metadata["url"] = url + metadata["params"] = params metadata["json"] = json - response = await self.request(metadata, "PATCH", url, json=json) + response = await self.request(metadata, "PATCH", url, params=params, json=json) if response: if response.content.strip(): return response.json() diff --git a/meraki/session/sync.py b/meraki/session/sync.py index b8eb5d27..b4867621 100644 --- a/meraki/session/sync.py +++ b/meraki/session/sync.py @@ -163,11 +163,12 @@ def get(self, metadata, url, params=None): response.close() return ret - def post(self, metadata, url, json=None): + def post(self, metadata, url, json=None, params=None): metadata["method"] = "POST" metadata["url"] = url + metadata["params"] = params metadata["json"] = json - response = self.request(metadata, "POST", url, json=json) + response = self.request(metadata, "POST", url, params=params, json=json) ret = None if response: if response.content.strip(): @@ -175,11 +176,12 @@ def post(self, metadata, url, json=None): response.close() return ret - def put(self, metadata, url, json=None): + def put(self, metadata, url, json=None, params=None): metadata["method"] = "PUT" metadata["url"] = url + metadata["params"] = params metadata["json"] = json - response = self.request(metadata, "PUT", url, json=json) + response = self.request(metadata, "PUT", url, params=params, json=json) ret = None if response: if response.content.strip(): @@ -187,11 +189,12 @@ def put(self, metadata, url, json=None): response.close() return ret - def patch(self, metadata, url, json=None): + def patch(self, metadata, url, json=None, params=None): metadata["method"] = "PATCH" metadata["url"] = url + metadata["params"] = params metadata["json"] = json - response = self.request(metadata, "PATCH", url, json=json) + response = self.request(metadata, "PATCH", url, params=params, json=json) ret = None if response: if response.content.strip(): diff --git a/tests/generator/test_generator_audit.py b/tests/generator/test_generator_audit.py index fc07f758..44d63864 100644 --- a/tests/generator/test_generator_audit.py +++ b/tests/generator/test_generator_audit.py @@ -192,5 +192,65 @@ def test_keyword_param_remapped_in_generated_function(): assert '"from"' in rendered +def _write_query_spec(): + return { + "paths": { + "/things": { + "post": { + "operationId": "claimThings", + "tags": ["organizations"], + "summary": "Claim things", + "parameters": [ + { + "name": "validate", + "in": "query", + "required": False, + "schema": {"type": "boolean"}, + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["name"], + "properties": {"name": {"type": "string", "description": "Thing name"}}, + } + } + } + }, + } + } + } + } + + +def test_write_operations_generate_query_params_for_all_clients(): + clear_cache() + spec = _write_query_spec() + section = {"/things": {"post": spec["paths"]["/things"]["post"]}} + output = io.StringIO() + async_output = io.StringIO() + batch_output = io.StringIO() + + generate_library.generate_standard_and_async_functions(_jinja_env(), TEMPLATE_DIR, section, output, async_output, spec) + generate_library.generate_action_batch_functions( + _jinja_env(), + TEMPLATE_DIR, + section, + batch_output, + [{"summary": "Claim things", "operation": "create"}], + spec, + ) + + for rendered in (output.getvalue(), async_output.getvalue()): + assert 'query_params = ["validate", ]' in rendered + assert "self._session.post(metadata, resource, payload, params=params)" in rendered + + batch_rendered = batch_output.getvalue() + assert 'query_params = ["validate", ]' in batch_rendered + assert 'resource += f"?{httpx.QueryParams(params)}"' in batch_rendered + + if __name__ == "__main__": sys.exit(pytest.main([__file__, "-q"])) From f8ef730299ed57b69199169543756353342e21f1 Mon Sep 17 00:00:00 2001 From: "John M. Kuchta" Date: Wed, 15 Jul 2026 17:27:37 -0700 Subject: [PATCH 10/11] fix: avoid empty batch query strings --- generator/batch_function_template.jinja2 | 3 ++- tests/generator/test_generator_audit.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/generator/batch_function_template.jinja2 b/generator/batch_function_template.jinja2 index 334ff656..d53d1ce3 100644 --- a/generator/batch_function_template.jinja2 +++ b/generator/batch_function_template.jinja2 @@ -46,7 +46,8 @@ {% endif %} {% if query_params|length > 0 %} - resource += f"?{httpx.QueryParams(params)}" + if params: + resource += f"?{httpx.QueryParams(params)}" {% endif %} {% if body_params|length > 0 and batch_operation != 'destroy' %} diff --git a/tests/generator/test_generator_audit.py b/tests/generator/test_generator_audit.py index 44d63864..c4744d95 100644 --- a/tests/generator/test_generator_audit.py +++ b/tests/generator/test_generator_audit.py @@ -249,7 +249,7 @@ def test_write_operations_generate_query_params_for_all_clients(): batch_rendered = batch_output.getvalue() assert 'query_params = ["validate", ]' in batch_rendered - assert 'resource += f"?{httpx.QueryParams(params)}"' in batch_rendered + assert 'if params:\n resource += f"?{httpx.QueryParams(params)}"' in batch_rendered if __name__ == "__main__": From c5e376b0c7763c80bdf3ba5317e4f10b3eaef0d1 Mon Sep 17 00:00:00 2001 From: "meraki-release-bot[bot]" <282373767+meraki-release-bot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 00:47:49 +0000 Subject: [PATCH 11/11] Auto-generated library v4.3.1 for API v1.72.0. (#453) Co-authored-by: GitHub Action --- docs/generation-report.md | 6 ++++++ meraki/_version.py | 2 +- meraki/aio/api/licensing.py | 18 ++++++++++++++---- meraki/aio/api/networks.py | 9 +++++++-- meraki/aio/api/switch.py | 9 +++++++-- meraki/api/batch/networks.py | 26 ++++++++++++++++++++++++++ meraki/api/batch/switch.py | 10 ++++++++++ meraki/api/licensing.py | 18 ++++++++++++++---- meraki/api/networks.py | 9 +++++++-- meraki/api/switch.py | 9 +++++++-- pyproject.toml | 2 +- uv.lock | 2 +- 12 files changed, 101 insertions(+), 19 deletions(-) diff --git a/docs/generation-report.md b/docs/generation-report.md index ffc35b2a..3196bdd3 100644 --- a/docs/generation-report.md +++ b/docs/generation-report.md @@ -1,5 +1,11 @@ # Generation Report +## 2026-07-16 | Library v4.3.1 | API 1.72.0 + + +No Python keyword parameter conflicts detected. + + ## 2026-07-09 | Library v4.3.0 | API 1.72.0 diff --git a/meraki/_version.py b/meraki/_version.py index 111dc917..ed48cdab 100644 --- a/meraki/_version.py +++ b/meraki/_version.py @@ -1 +1 @@ -__version__ = "4.3.0" +__version__ = "4.3.1" diff --git a/meraki/aio/api/licensing.py b/meraki/aio/api/licensing.py index 962e7654..553f47ea 100644 --- a/meraki/aio/api/licensing.py +++ b/meraki/aio/api/licensing.py @@ -132,6 +132,11 @@ def claimAdministeredLicensingSubscriptionSubscriptions(self, claimKey: str, org } resource = "/administered/licensing/subscription/subscriptions/claim" + query_params = [ + "validate", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + body_params = [ "claimKey", "organizationId", @@ -141,14 +146,14 @@ def claimAdministeredLicensingSubscriptionSubscriptions(self, claimKey: str, org payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} if self._session._validate_kwargs: - all_params = [] + body_params + all_params = query_params + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning( f"claimAdministeredLicensingSubscriptionSubscriptions: ignoring unrecognized kwargs: {invalid}" ) - return self._session.post(metadata, resource, payload) + return self._session.post(metadata, resource, payload, params=params) def validateAdministeredLicensingSubscriptionSubscriptionsClaimKey(self, claimKey: str, **kwargs): """ @@ -242,20 +247,25 @@ def bindAdministeredLicensingSubscriptionSubscription(self, subscriptionId: str, subscriptionId = urllib.parse.quote(str(subscriptionId), safe="") resource = f"/administered/licensing/subscription/subscriptions/{subscriptionId}/bind" + query_params = [ + "validate", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + body_params = [ "networkIds", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} if self._session._validate_kwargs: - all_params = [] + body_params + all_params = query_params + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning( f"bindAdministeredLicensingSubscriptionSubscription: ignoring unrecognized kwargs: {invalid}" ) - return self._session.post(metadata, resource, payload) + return self._session.post(metadata, resource, payload, params=params) def getOrganizationLicensingCotermLicenses(self, organizationId: str, total_pages=1, direction="next", **kwargs): """ diff --git a/meraki/aio/api/networks.py b/meraki/aio/api/networks.py index 83c085c0..34865da2 100644 --- a/meraki/aio/api/networks.py +++ b/meraki/aio/api/networks.py @@ -806,6 +806,11 @@ def claimNetworkDevices(self, networkId: str, serials: list, **kwargs): networkId = urllib.parse.quote(str(networkId), safe="") resource = f"/networks/{networkId}/devices/claim" + query_params = [ + "addAtomically", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + body_params = [ "serials", "detailsByDevice", @@ -813,12 +818,12 @@ def claimNetworkDevices(self, networkId: str, serials: list, **kwargs): payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} if self._session._validate_kwargs: - all_params = [] + body_params + all_params = query_params + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning(f"claimNetworkDevices: ignoring unrecognized kwargs: {invalid}") - return self._session.post(metadata, resource, payload) + return self._session.post(metadata, resource, payload, params=params) def vmxNetworkDevicesClaim(self, networkId: str, size: str, **kwargs): """ diff --git a/meraki/aio/api/switch.py b/meraki/aio/api/switch.py index 21dcc763..ab988ac5 100644 --- a/meraki/aio/api/switch.py +++ b/meraki/aio/api/switch.py @@ -2096,6 +2096,11 @@ def updateNetworkSwitchRoutingOspf(self, networkId: str, **kwargs): networkId = urllib.parse.quote(str(networkId), safe="") resource = f"/networks/{networkId}/switch/routing/ospf" + query_params = [ + "vrf", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + body_params = [ "enabled", "helloTimerInSeconds", @@ -2108,12 +2113,12 @@ def updateNetworkSwitchRoutingOspf(self, networkId: str, **kwargs): payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} if self._session._validate_kwargs: - all_params = [] + body_params + all_params = query_params + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning(f"updateNetworkSwitchRoutingOspf: ignoring unrecognized kwargs: {invalid}") - return self._session.put(metadata, resource, payload) + return self._session.put(metadata, resource, payload, params=params) def getNetworkSwitchSettings(self, networkId: str): """ diff --git a/meraki/api/batch/networks.py b/meraki/api/batch/networks.py index b40f4cc8..c7113741 100644 --- a/meraki/api/batch/networks.py +++ b/meraki/api/batch/networks.py @@ -1,5 +1,7 @@ import urllib +import httpx + class ActionBatchNetworks(object): def __init__(self): @@ -137,6 +139,14 @@ def claimNetworkDevices(self, networkId: str, serials: list, **kwargs): networkId = urllib.parse.quote(str(networkId), safe="") resource = f"/networks/{networkId}/devices/claim" + query_params = [ + "addAtomically", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + + if params: + resource += f"?{httpx.QueryParams(params)}" + body_params = [ "serials", "detailsByDevice", @@ -652,6 +662,14 @@ def deleteNetworkGroupPolicy(self, networkId: str, groupPolicyId: str, **kwargs) groupPolicyId = urllib.parse.quote(str(groupPolicyId), safe="") resource = f"/networks/{networkId}/groupPolicies/{groupPolicyId}" + query_params = [ + "force", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + + if params: + resource += f"?{httpx.QueryParams(params)}" + action = { "resource": resource, "operation": "destroy", @@ -717,6 +735,14 @@ def deleteNetworkMerakiAuthUser(self, networkId: str, merakiAuthUserId: str, **k merakiAuthUserId = urllib.parse.quote(str(merakiAuthUserId), safe="") resource = f"/networks/{networkId}/merakiAuthUsers/{merakiAuthUserId}" + query_params = [ + "delete", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + + if params: + resource += f"?{httpx.QueryParams(params)}" + action = { "resource": resource, "operation": "destroy", diff --git a/meraki/api/batch/switch.py b/meraki/api/batch/switch.py index 670ef832..9c0662b8 100644 --- a/meraki/api/batch/switch.py +++ b/meraki/api/batch/switch.py @@ -1,5 +1,7 @@ import urllib +import httpx + class ActionBatchSwitch(object): def __init__(self): @@ -1191,6 +1193,14 @@ def updateNetworkSwitchRoutingOspf(self, networkId: str, **kwargs): networkId = urllib.parse.quote(str(networkId), safe="") resource = f"/networks/{networkId}/switch/routing/ospf" + query_params = [ + "vrf", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + + if params: + resource += f"?{httpx.QueryParams(params)}" + body_params = [ "enabled", "helloTimerInSeconds", diff --git a/meraki/api/licensing.py b/meraki/api/licensing.py index df89824b..15d31df9 100644 --- a/meraki/api/licensing.py +++ b/meraki/api/licensing.py @@ -132,6 +132,11 @@ def claimAdministeredLicensingSubscriptionSubscriptions(self, claimKey: str, org } resource = "/administered/licensing/subscription/subscriptions/claim" + query_params = [ + "validate", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + body_params = [ "claimKey", "organizationId", @@ -141,14 +146,14 @@ def claimAdministeredLicensingSubscriptionSubscriptions(self, claimKey: str, org payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} if self._session._validate_kwargs: - all_params = [] + body_params + all_params = query_params + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning( f"claimAdministeredLicensingSubscriptionSubscriptions: ignoring unrecognized kwargs: {invalid}" ) - return self._session.post(metadata, resource, payload) + return self._session.post(metadata, resource, payload, params=params) def validateAdministeredLicensingSubscriptionSubscriptionsClaimKey(self, claimKey: str, **kwargs): """ @@ -242,20 +247,25 @@ def bindAdministeredLicensingSubscriptionSubscription(self, subscriptionId: str, subscriptionId = urllib.parse.quote(str(subscriptionId), safe="") resource = f"/administered/licensing/subscription/subscriptions/{subscriptionId}/bind" + query_params = [ + "validate", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + body_params = [ "networkIds", ] payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} if self._session._validate_kwargs: - all_params = [] + body_params + all_params = query_params + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning( f"bindAdministeredLicensingSubscriptionSubscription: ignoring unrecognized kwargs: {invalid}" ) - return self._session.post(metadata, resource, payload) + return self._session.post(metadata, resource, payload, params=params) def getOrganizationLicensingCotermLicenses(self, organizationId: str, total_pages=1, direction="next", **kwargs): """ diff --git a/meraki/api/networks.py b/meraki/api/networks.py index c1858a71..ea29c61f 100644 --- a/meraki/api/networks.py +++ b/meraki/api/networks.py @@ -806,6 +806,11 @@ def claimNetworkDevices(self, networkId: str, serials: list, **kwargs): networkId = urllib.parse.quote(str(networkId), safe="") resource = f"/networks/{networkId}/devices/claim" + query_params = [ + "addAtomically", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + body_params = [ "serials", "detailsByDevice", @@ -813,12 +818,12 @@ def claimNetworkDevices(self, networkId: str, serials: list, **kwargs): payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} if self._session._validate_kwargs: - all_params = [] + body_params + all_params = query_params + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning(f"claimNetworkDevices: ignoring unrecognized kwargs: {invalid}") - return self._session.post(metadata, resource, payload) + return self._session.post(metadata, resource, payload, params=params) def vmxNetworkDevicesClaim(self, networkId: str, size: str, **kwargs): """ diff --git a/meraki/api/switch.py b/meraki/api/switch.py index 86ac6cc3..4004ce53 100644 --- a/meraki/api/switch.py +++ b/meraki/api/switch.py @@ -2096,6 +2096,11 @@ def updateNetworkSwitchRoutingOspf(self, networkId: str, **kwargs): networkId = urllib.parse.quote(str(networkId), safe="") resource = f"/networks/{networkId}/switch/routing/ospf" + query_params = [ + "vrf", + ] + params = {k.strip(): v for k, v in kwargs.items() if k.strip() in query_params} + body_params = [ "enabled", "helloTimerInSeconds", @@ -2108,12 +2113,12 @@ def updateNetworkSwitchRoutingOspf(self, networkId: str, **kwargs): payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params} if self._session._validate_kwargs: - all_params = [] + body_params + all_params = query_params + body_params invalid = [k for k in kwargs if k.strip() not in all_params and k != "self"] if invalid and self._session._logger: self._session._logger.warning(f"updateNetworkSwitchRoutingOspf: ignoring unrecognized kwargs: {invalid}") - return self._session.put(metadata, resource, payload) + return self._session.put(metadata, resource, payload, params=params) def getNetworkSwitchSettings(self, networkId: str): """ diff --git a/pyproject.toml b/pyproject.toml index 0bc08619..fa88ea59 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "meraki" -version = "4.3.0" +version = "4.3.1" description = "Cisco Meraki Dashboard API library" authors = [ {name = "Cisco Meraki", email = "api-feedback@meraki.net"} diff --git a/uv.lock b/uv.lock index 701593d8..498e0262 100644 --- a/uv.lock +++ b/uv.lock @@ -363,7 +363,7 @@ wheels = [ [[package]] name = "meraki" -version = "4.3.0" +version = "4.3.1" source = { editable = "." } dependencies = [ { name = "httpx" },