From dab6bd8027c38b28e7c2fd31d306475672efb72f Mon Sep 17 00:00:00 2001 From: Allan Stockman Rugano Date: Wed, 22 Jul 2026 17:16:55 +0200 Subject: [PATCH 1/3] Upgraded to modern python --- .coverage | Bin 0 -> 69632 bytes .github/workflows/ci.yml | 44 + .gitignore | 2 +- .pre-commit-config.yaml | 18 + .travis.yml | 10 - CHANGELOG.md | 37 + LICENSE.txt | 2 +- MANIFEST.in | 4 - Makefile | 46 - README.md | 153 +++ README.rst | 122 -- docs/api/client.md | 3 + docs/api/models.md | 3 + docs/dmp.md | 95 ++ docs/getting-started.md | 54 + docs/index.md | 19 + docs/ipn.md | 63 + docs/par.md | 110 ++ docs/per.md | 46 + docs/psr.md | 89 ++ mkdocs.yml | 33 + paydunya/__init__.py | 156 --- paydunya/direct_payments.py | 23 - paydunya/invoice.py | 131 -- paydunya/opr.py | 45 - pyproject.toml | 90 +- requirements.txt | 6 - runtests.py | 2287 ----------------------------------- setup.py | 88 -- src/paydunya/__init__.py | 34 + src/paydunya/client.py | 99 ++ src/paydunya/direct_pay.py | 14 + src/paydunya/dmp.py | 39 + src/paydunya/exceptions.py | 19 + src/paydunya/invoice.py | 117 ++ src/paydunya/ipn.py | 9 + src/paydunya/models.py | 64 + src/paydunya/py.typed | 0 tests/__init__.py | 6 - tests/conftest.py | 29 + tests/test_client.py | 115 ++ tests/test_compat.py | 109 ++ tests/test_direct_pay.py | 28 + tests/test_dmp.py | 145 +++ tests/test_general.py | 37 - tests/test_init.py | 7 + tests/test_invoice.py | 311 ++++- tests/test_ipn.py | 33 + tests/test_opr.py | 37 - tox.ini | 20 +- uv.lock | 1176 ++++++++++++++++++ 51 files changed, 3170 insertions(+), 3057 deletions(-) create mode 100644 .coverage create mode 100644 .github/workflows/ci.yml create mode 100644 .pre-commit-config.yaml delete mode 100644 .travis.yml create mode 100644 CHANGELOG.md delete mode 100644 MANIFEST.in delete mode 100644 Makefile create mode 100644 README.md delete mode 100644 README.rst create mode 100644 docs/api/client.md create mode 100644 docs/api/models.md create mode 100644 docs/dmp.md create mode 100644 docs/getting-started.md create mode 100644 docs/index.md create mode 100644 docs/ipn.md create mode 100644 docs/par.md create mode 100644 docs/per.md create mode 100644 docs/psr.md create mode 100644 mkdocs.yml delete mode 100644 paydunya/__init__.py delete mode 100644 paydunya/direct_payments.py delete mode 100644 paydunya/invoice.py delete mode 100644 paydunya/opr.py delete mode 100644 requirements.txt delete mode 100644 runtests.py delete mode 100644 setup.py create mode 100644 src/paydunya/__init__.py create mode 100644 src/paydunya/client.py create mode 100644 src/paydunya/direct_pay.py create mode 100644 src/paydunya/dmp.py create mode 100644 src/paydunya/exceptions.py create mode 100644 src/paydunya/invoice.py create mode 100644 src/paydunya/ipn.py create mode 100644 src/paydunya/models.py create mode 100644 src/paydunya/py.typed delete mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_client.py create mode 100644 tests/test_compat.py create mode 100644 tests/test_direct_pay.py create mode 100644 tests/test_dmp.py delete mode 100644 tests/test_general.py create mode 100644 tests/test_init.py create mode 100644 tests/test_ipn.py delete mode 100644 tests/test_opr.py create mode 100644 uv.lock diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..3ec550a2b777a796d657e97404599515ef962845 GIT binary patch literal 69632 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 G+5ZoN^@eEx literal 0 HcmV?d00001 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9453653 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,44 @@ +name: CI + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + with: + python-version: "3.13" + - run: uv sync --dev + - run: uv run ruff check src/paydunya tests + - run: uv run ruff format --check src/paydunya tests + + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + with: + python-version: ${{ matrix.python-version }} + - run: uv sync --dev + - run: uv run pytest --cov --cov-report=term + + build: + runs-on: ubuntu-latest + needs: [lint, test] + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + - run: uv build + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ diff --git a/.gitignore b/.gitignore index 5ccf63a..d38f39c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ MANIFEST *~ */#* .#* -/test.py \ No newline at end of file +/test.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9458fcd --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,18 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-toml + - id: check-added-large-files + - id: mixed-line-ending + args: ["--fix=lf"] + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.5.0 + hooks: + - id: ruff + args: ["--fix"] + - id: ruff-format diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 78884d7..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: python -python: - - "2.6" - - "2.7" - - "3.2" - - "3.3" -# command to install dependencies -install: "pip install -r requirements.txt" -# command to run tests -script: nosetests \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b7c0ce2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,37 @@ +# Changelog + +## 2.0.0 (2026-07-22) + +### Breaking Changes +- Complete rewrite with modern tooling and API design +- `PaydunyaClient(master_key, private_key, token, mode="test"|"live")` replaces + the old `paydunya.debug` and `paydunya.api_keys` module-level globals +- **OPR removed** — the `opr/create` and `opr/charge` endpoints no longer exist + in PayDunya's current documentation. Use the JavaScript-based PSR flow + (documented at https://developers.paydunya.com/doc/EN/psr_plugins/api_psr) + where your server creates a checkout invoice and returns the token +- Python 3.10+ only (dropped all Python 2 and Python < 3.10 support) +- `SimpleJSON` fallback removed +- `httpx` replaces `requests` + +### Added +- **DMP API** — Payment Request API: send invoices via SMS/Email + (`DMP.create()` / `DMP.check_status()`) +- **IPN helper** — `verify_ipn_hash()` for SHA-512 hash verification on callbacks +- **Customer pre-fill** — `Invoice.set_customer(name, email, phone)` to pre-fill + payment page fields +- **Docs-compliant items format** — items now keyed as `item_0`, `item_1`, ... + matching the official HTTP/JSON documentation +- Type hints throughout, `py.typed` marker +- Pytest-based test suite with httpx mocking (no network required) +- MkDocs Material documentation in `docs/` + +### Changed +- Package layout: `src/paydunya/` (PEP 621) +- Build system: hatchling instead of setuptools/setup.py +- Linting: ruff replaces flake8/pep8/pyflakes +- CI: GitHub Actions replaces Travis CI +- uv for dependency management + +## 1.0.7 +- Last stable release under the old architecture diff --git a/LICENSE.txt b/LICENSE.txt index 0f113c0..b463c67 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 57f146b..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -# file GENERATED by distutils, do NOT edit -include README.rst LICENSE.txt runtests.py -recursive-include paydunya * -recursive-include tests * diff --git a/Makefile b/Makefile deleted file mode 100644 index d24ce51..0000000 --- a/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -.PHONY: help clean clean-pyc clean-build list test test-all coverage docs release sdist - -help: - @echo "clean-build - remove build artifacts" - @echo "clean-pyc - remove Python file artifacts" - @echo "lint - check style with flake8" - @echo "test - run tests quickly with the default Python" - @echo "testall - run tests on every Python version with tox" - @echo "coverage - check code coverage quickly with the default Python" - @echo "release - package and upload a release" - @echo "sdist - package" - -clean: clean-build clean-pyc - -clean-build: - rm -fr build/ - rm -fr dist/ - rm -fr *.egg-info - -clean-pyc: - find . -name '*.pyc' -exec rm -f {} + - find . -name '*.pyo' -exec rm -f {} + - find . -name '*~' -exec rm -f {} + - -lint: - flake8 paydunya tests - -test: clean - py.test -s - -test-all: - tox - -coverage: - coverage run --source paydunya setup.py test - coverage report -m - coverage html - open htmlcov/index.html - -release: clean test - python setup.py sdist upload - python setup.py bdist_wheel upload - -sdist: clean test - python setup.py sdist - ls -l dist/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e07e063 --- /dev/null +++ b/README.md @@ -0,0 +1,153 @@ +# PayDunya Python SDK + +[![CI](https://github.com/paydunyadev/paydunya-python-master/actions/workflows/ci.yml/badge.svg)](https://github.com/paydunyadev/paydunya-python-master/actions/workflows/ci.yml) +[![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://pypi.org/project/paydunya/) +[![PyPI](https://img.shields.io/pypi/v/paydunya.svg)](https://pypi.org/project/paydunya/) + +Python client library for integrating [PayDunya](https://paydunya.com) payment services — mobile money, card payments, and more for businesses across West Africa. + +## Features + +- **PAR** — Payment And Redirection: create invoices and redirect customers to PayDunya's payment page +- **PSR** — Payment Without Redirection: server-side token generation for the JavaScript popup flow +- **PER** — Payment And Redistribution (DirectPay): transfer funds to other PayDunya accounts +- **DMP** — Payment Request API: send payment links to customers via SMS or Email +- **IPN** — Instant Payment Notification hash verification helper +- Fully typed, `httpx`-based transport, Python 3.10+ + +## Installation + +```bash +uv add paydunya +# or +pip install paydunya +``` + +## Quick Start + +```python +from paydunya import Invoice, InvoiceItem, PaydunyaClient, Store + +client = PaydunyaClient( + master_key="wQzk9ZwR-Qq9m-0hD0-zpud-je5coGC3FHKW", + private_key="test_private_rMIdJM3PLLhLjyArx9tF3VURAF5", + token="IivOiOxGJuWhc5znlIiK", + mode="test", +) + +store = Store(name="Sandra's Store") +items = [ + InvoiceItem( + name="Croco shoes", + quantity=3, + unit_price="10000", + total_price="30000", + description="Shoes made of genuine crocodile skin", + ), + InvoiceItem( + name="Ice Shirt", + quantity=1, + unit_price="5000", + total_price="5000", + ), +] + +invoice = Invoice(client, store) +invoice.add_items(items) +invoice.add_tax("TVA (18%)", 6300) +invoice.set_total_amount(42300) +invoice.set_description("Payment for items from Sandra's Store") +invoice.set_customer(name="John Doe", email="john@example.com", phone="771111111") +invoice.set_return_url("https://my-shop.com/thanks") +invoice.set_cancel_url("https://my-shop.com/cancelled") +invoice.set_callback_url("https://my-shop.com/ipn") + +response = invoice.create() +print(response["response_text"]) # payment page URL + +status = invoice.confirm(response["token"]) +print(status["status"]) # pending, completed, cancelled, failed +``` + +## DMP — Payment Requests via SMS/Email + +```python +from paydunya import DMP, PaydunyaClient + +client = PaydunyaClient( + master_key="...", private_key="...", token="...", + mode="live", +) + +dmp = DMP(client) + +result = dmp.create( + amount=5000, + recipient_email="customer@example.com", + support_fees=True, + send_notification=False, +) +print(result["url"]) # payment link to include in your custom message +print(result["reference_number"]) + +status = dmp.check_status(result["reference_number"]) +print(status["status"]) # pending, completed, failed +``` + +## DirectPay (PER) + +```python +from paydunya import DirectPay, PaydunyaClient + +client = PaydunyaClient(master_key="...", private_key="...", token="...") +dp = DirectPay(client) +response = dp.pay(account_alias="774563209", amount=215000) +print(response["transaction_id"]) +``` + +## IPN Verification + +```python +from paydunya import verify_ipn_hash + +if verify_ipn_hash( + master_key="your-master-key", + received_hash=request.POST["data"]["hash"], +): + # data genuinely comes from PayDunya + status = request.POST["data"]["status"] +``` + +## API Keys + +Register at [paydunya.com/integration-setups](https://paydunya.com/integration-setups), create an application, and retrieve your three keys: + +- `PAYDUNYA-MASTER-KEY` — main application key +- `PAYDUNYA-PRIVATE-KEY` — private key (`test_private_...` or `live_private_...`) +- `PAYDUNYA-TOKEN` — application token + +Use `mode="test"` for sandbox testing and `mode="live"` for production. + +## Migration from v1.x + +The v2.0 API has been redesigned: + +- `PaydunyaClient(master_key, private_key, token, mode="test")` replaces the old `paydunya.debug` / `paydunya.api_keys` globals +- `OPR` has been removed — use the PSR JavaScript flow documented at [developers.paydunya.com](https://developers.paydunya.com/doc/EN/psr_plugins/api_psr) +- `Invoice.confirm(token)` is now a clear method (not auto-using `self._response`) +- Items are now keyed `item_0`, `item_1` (docs-compliant, formerly a flat array started from `item_1`) +- `Invoice.customer` pre-fill is now supported via `set_customer()` + +## Development + +```bash +uv sync --dev # install all dependencies +uv run pytest # run tests +uv run ruff check . # lint +uv run tox # test across Python 3.10–3.13 +uv build # build distribution packages +``` + +## License + +MIT — see [LICENSE.txt](LICENSE.txt) diff --git a/README.rst b/README.rst deleted file mode 100644 index a3afe5e..0000000 --- a/README.rst +++ /dev/null @@ -1,122 +0,0 @@ -PAYDUNYA Python Client Library -============================== - -This is a Python library for accessing the PAYDUNYA HTTP API. - -Installation ------------- - -.. code-block:: bash - - $ sudo pip install paydunya - $ OR git clone https://github.com/paydunyadev/paydunya-python-master.git - $ cd paydunya-python-master; python setup.py install - $ nosetests tests/ # run unit tests - -Read about `nosetests`_ - -Usage ------ - - -.. code-block:: python - - import paydunya - from paydunya import InvoiceItem, Store - - # runtime configs - PAYDUNYA_ACCESS_TOKENS = { - 'PAYDUNYA-MASTER-KEY': "Your PAYDUNYA master key", - 'PAYDUNYA-PRIVATE-KEY': "Your PAYDUNYA private key", - 'PAYDUNYA-TOKEN': "Your PAYDUNYA token" - } - # defaults to False - paydunya.debug = True - # set the access/api keys - paydunya.api_keys = PAYDUNYA_ACCESS_TOKENS - - # Invoice - store = Store(name='Magasin Chez Sandra') - items = [ - InvoiceItem( - name="Clavier DELL", - quantity=2, - unit_price="3000", - total_price="6000", - description="Best Keyboard of the 2015 year" - ), - InvoiceItem( - name="Ordinateur Lenovo L440", - quantity=1, - unit_price="400000", - total_price="400000", - description="Powerful and slim" - ), - ] - invoice = paydunya.Invoice(store) - invoice.add_items(items) - # taxes are (key,value) pairs - invoice.add_taxes([("Other TAX", 5000), ("TVA (18%)", 700)]) - invoice.add_custom_data([ - ("first_name", "Alioune"), - ("last_name", "Badara"), - ("cart_id", 97628), - ("coupon", "NOEL"), - ]) - - # you can also pass the items, taxes, custom to the `create` method - successful, response = invoice.create() - if successful: - do_something_with_resp(response) - - # confirm invoice - invoice.confirm('YOUR_INVOICE_TOKEN') - - - # PSR - opr_data = { - 'account_alias': 'EMAIL_OU_NUMERO_DU_CLIENT_PAYDUNYA', - 'description': 'Hello World', - 'total_amount': 6500 - } - store = paydunya.Store(name='Magasin Chez Sandra') - opr = paydunya.OPR(opr_data, store) - # You can also pass the data to the `create` function - successful, response = opr.create() - if successful: - do_something_with_response(response) - status, _ = opr.charge({ - 'token': token, - 'confirm_token': user_submitted_token - }) - - # Direct Pay - account_alias = "EMAIL_OU_NUMERO_DU_CLIENT_PAYDUNYA" - amount = 6500 - # toggle debug switch to True - direct_pay = paydunya.DirectPay(account_alias, amount) - status, response = direct_pay.process() - - -License -------- -see LICENSE.txt - - -Contributing ------------- -Issues, forks, and pull requests are welcome! - - -Note ----- -- Some of the API calls require formal approval from PAYDUNYA -- For more information, please read the `PAYDUNYA HTTP API`_ -- Tested on Python 2.7, and 3+. - -.. _nosetests: https://nose.readthedocs.io/en/latest/ -.. _PAYDUNYA HTTP API: https://paydunya.com/developers/http - -Authors --------- -PAYDUNYA diff --git a/docs/api/client.md b/docs/api/client.md new file mode 100644 index 0000000..c98efdb --- /dev/null +++ b/docs/api/client.md @@ -0,0 +1,3 @@ +# Client + +::: paydunya.client diff --git a/docs/api/models.md b/docs/api/models.md new file mode 100644 index 0000000..87d88af --- /dev/null +++ b/docs/api/models.md @@ -0,0 +1,3 @@ +# Models + +::: paydunya.models diff --git a/docs/dmp.md b/docs/dmp.md new file mode 100644 index 0000000..32aba70 --- /dev/null +++ b/docs/dmp.md @@ -0,0 +1,95 @@ +# DMP — Payment Request API + +The **DMP API** allows you to send payment requests to your customers via +SMS or Email. The customer receives a link they can click to pay using +their preferred method. + +!!! warning + The DMP API operates in **live mode only** (error `4001` is returned if + keys are not in live mode). Use your production keys. + +## Creating a Payment Request + +```python +from paydunya import DMP, PaydunyaClient + +client = PaydunyaClient( + master_key="your-live-master-key", + private_key="live_private_...", + token="your-live-token", + mode="live", +) + +dmp = DMP(client) +result = dmp.create( + amount=1250, # between 200 and 3,000,000 + recipient_email="customer@example.com", + recipient_phone="771234567", # at least one of email/phone required + support_fees=True, # True = you pay the fees, False = customer pays + send_notification=True, # True = PayDunya sends the SMS/Email +) +``` + +### Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `amount` | int/float | Yes | Amount between 200 and 3,000,000 | +| `recipient_email` | str | At least one | Recipient's email address | +| `recipient_phone` | str | At least one | Recipient's phone number | +| `support_fees` | bool | No (default `False`) | `True` = you absorb fees, `False` = customer pays | +| `send_notification` | bool | No (default `True`) | `True` = PayDunya sends the message, `False` = you handle it | + +### Response with `send_notification=True` + +```json +{ + "success": true, + "message": "Your payment request has been sent successfully." +} +``` + +### Response with `send_notification=False` + +```json +{ + "response-code": "00", + "reference_number": "4190239470044", + "url": "https://pydu.me/k5Rrrj", + "description": "Your payment request has been created successfully" +} +``` + +When `send_notification=False`, PayDunya returns a short URL and a reference number. +You can include these in your own custom SMS or Email messages. + +## Checking Status + +```python +status = dmp.check_status("4190239470044") +print(status["status"]) # pending, completed, or failed +``` + +### Response + +```json +{ + "response-code": "00", + "status": "pending" +} +``` + +Status values: +- `pending` — payment not yet made +- `completed` — payment received successfully +- `failed` — payment attempt failed + +## Error Codes + +| Code | Meaning | +|------|---------| +| `00` | Success | +| `4000` | Malformed request (missing keys or recipient) | +| `4001` | Integration mode must be live | +| `1000` | Invalid API keys | +| `4004` | Payment request not found (on status check) | diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..f4adb85 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,54 @@ +# Getting Started + +## Installation + +```bash +uv add paydunya +# or +pip install paydunya +``` + +## API Keys + +1. Create a [PayDunya Business account](https://paydunya.com/signup) +2. Go to [Integration API](https://paydunya.com/integration-setups) +3. Create a new application ("AppDunya") +4. Choose **Test mode** and **Enable production mode** +5. Retrieve your three API keys from the application details page + +You'll receive: +- `PAYDUNYA-MASTER-KEY` — main key +- `PAYDUNYA-PRIVATE-KEY` — private key (`test_private_...` or `live_private_...`) +- `PAYDUNYA-TOKEN` — application token + +## Test Mode + +In test mode, use your test keys and create [fictitious customer accounts](https://paydunya.com/integration-setups/sandbox-accounts) in the dashboard to simulate payments. Payments are deducted from the fictitious customer's balance. + +```python +from paydunya import PaydunyaClient + +client = PaydunyaClient( + master_key="your-master-key", + private_key="test_private_...", + token="your-token", + mode="test", +) +``` + +## Production + +When ready: + +1. Update your application configuration in the dashboard: **Enable production mode** → **Yes** +2. Replace test keys with production keys +3. Switch to `mode="live"` + +```python +client = PaydunyaClient( + master_key="your-live-master-key", + private_key="live_private_...", + token="your-live-token", + mode="live", +) +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..dd0e191 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,19 @@ +# PayDunya Python SDK + +Python client library for [PayDunya](https://paydunya.com) payment services. + +## Supported APIs + +| API | Description | Module | +|-----|-------------|--------| +| **PAR** | Payment And Redirection — redirect customers to PayDunya's payment page | `invoice` | +| **PSR** | Payment Without Redirection — generate tokens for the JavaScript popup flow | `invoice` (server-side token) | +| **PER** | Payment And Redistribution — transfer funds to other PayDunya accounts | `direct_pay` | +| **DMP** | Payment Request API — send payment links via SMS/Email | `dmp` | +| **IPN** | Instant Payment Notification hash verification | `ipn` | + +## Quick Links + +- [PayDunya Developer Documentation](https://developers.paydunya.com/) +- [API Key Setup](https://paydunya.com/integration-setups) +- [Available Payment Channels](https://developers.paydunya.com/doc/EN/introduction#section-8) diff --git a/docs/ipn.md b/docs/ipn.md new file mode 100644 index 0000000..6375bdb --- /dev/null +++ b/docs/ipn.md @@ -0,0 +1,63 @@ +# IPN — Instant Payment Notification + +PayDunya can POST payment transaction data to a callback URL (`callback_url`) +that you specify when creating an invoice. This is the most reliable way to +confirm payments, especially when they complete asynchronously (e.g., customer +confirming on their phone). + +## The Callback Data + +PayDunya POSTs `application/x-www-form-urlencoded` data to your endpoint with +the payment information nested under the `data` key. + +## Verifying the IPN Hash + +Every IPN response includes a `hash` field which is the **SHA-512 hash of your +Master Key**. You must compute this hash yourself and compare it to verify the +data genuinely comes from PayDunya. + +```python +from paydunya import verify_ipn_hash + +def ipn_handler(request): + data = request.POST["data"] + received_hash = data["hash"] + + if not verify_ipn_hash(master_key="your-master-key", received_hash=received_hash): + return "Unauthorized", 403 + + status = data["status"] + if status == "completed": + # Process the successful payment + print(f"Payment {data['invoice']['token']} completed") + + return "OK", 200 +``` + +## IPN Data Structure + +```json +{ + "data": { + "response_code": "00", + "response_text": "Transaction Found", + "hash": "8c6666a27fe5daeb76dae6abc7308a557...", + "status": "completed", + "mode": "test", + "invoice": { + "token": "test_jkEdPY8SuG", + "total_amount": 42300, + "description": "...", + "items": { "item_0": { ... }, "item_1": { ... } }, + "taxes": { "tax_0": { ... } } + }, + "customer": { + "name": "Alioune Faye", + "phone": "774563209", + "email": "alioune@example.com" + }, + "custom_data": { ... }, + "receipt_url": "https://paydunya.com/.../receipt/pdf/...pdf" + } +} +``` diff --git a/docs/par.md b/docs/par.md new file mode 100644 index 0000000..9db4f15 --- /dev/null +++ b/docs/par.md @@ -0,0 +1,110 @@ +# PAR — Payment And Redirection + +The **PAR API** is PayDunya's primary payment flow, recommended for 99% of use cases. +You create an invoice, redirect the customer to PayDunya's payment page, and confirm +the result afterward. + +## Workflow + +1. Build an invoice with items, taxes, customer info (optional) +2. Set the total amount (PayDunya bills this exact amount) +3. Call `invoice.create()` — get a `token` and a payment page URL (`response_text`) +4. Redirect the customer to the URL +5. After payment, confirm via `invoice.confirm(token)` or handle the IPN callback + +## Example + +```python +from paydunya import Invoice, InvoiceItem, PaydunyaClient, Store + +client = PaydunyaClient( + master_key="your-master-key", + private_key="test_private_...", + token="your-token", + mode="test", +) + +store = Store(name="My Shop") +items = [ + InvoiceItem( + name="Croco shoes", + quantity=3, + unit_price="10000", + total_price="30000", + description="Genuine crocodile skin", + ), + InvoiceItem( + name="Ice Shirt", + quantity=1, + unit_price="5000", + total_price="5000", + ), +] + +invoice = Invoice(client, store) +invoice.add_items(items) +invoice.add_tax("TVA (18%)", 6300) +invoice.add_tax("Delivery", 1000) +invoice.set_total_amount(42300) +invoice.set_description("Payment for items from My Shop") + +response = invoice.create() +# response["response_text"] contains the payment page URL +# response["token"] is the invoice token for confirmation + +# After the customer pays, confirm: +status = invoice.confirm(response["token"]) +print(status["status"]) # pending, completed, cancelled, or failed +``` + +## Customer Pre-fill + +Pre-fill the name, email, and phone on the payment page: + +```python +invoice.set_customer( + name="John Doe", + email="john@example.com", + phone="771111111", +) +``` + +## Restricting Payment Channels + +```python +invoice.add_channels(["card", "wave-senegal", "orange-money-senegal"]) +``` + +Available channel slugs are in the [introduction documentation](https://developers.paydunya.com/doc/EN/introduction#section-8). + +## Redirect URLs + +```python +invoice.set_cancel_url("https://my-shop.com/cancelled") +invoice.set_return_url("https://my-shop.com/thanks") # token appended as ?token=... +invoice.set_callback_url("https://my-shop.com/ipn") # IPN endpoint +``` + +## Custom Data + +Store extra data that is returned on confirmation but never displayed to the customer: + +```python +invoice.add_custom_data({ + "cart_id": 97628, + "coupon": "SUMMER25", +}) +``` + +## Confirming an Invoice + +```python +result = invoice.confirm(token) + +print(result["status"]) # pending, completed, cancelled, failed +print(result["customer"]) # customer info filled during payment +print(result["receipt_url"]) # PDF receipt URL +print(result["invoice"]) # full invoice data +print(result["custom_data"]) # your stored custom data +print(result["hash"]) # SHA-512 of your master key — verify via verify_ipn_hash() +``` diff --git a/docs/per.md b/docs/per.md new file mode 100644 index 0000000..52cea2a --- /dev/null +++ b/docs/per.md @@ -0,0 +1,46 @@ +# PER — Payment And Redistribution (DirectPay) + +The **PER API** (also called DirectPay) allows you to transfer funds from your +PayDunya account to another PayDunya account (identified by email or phone number). + +Use cases include marketplace payouts, supplier payments, or building your own +payment solution on top of PayDunya. + +!!! warning + The DirectPay service must be explicitly enabled in your application + configuration in the PayDunya dashboard. + +## Usage + +```python +from paydunya import DirectPay, PaydunyaClient + +client = PaydunyaClient( + master_key="your-master-key", + private_key="your-private-key", + token="your-token", + mode="live", +) + +direct_pay = DirectPay(client) +response = direct_pay.pay( + account_alias="774563209", # recipient's PayDunya email or phone + amount=6500, # amount in FCFA +) + +print(response["response_text"]) # "Transaction completed successfully" +print(response["transaction_id"]) # e.g., "TEST000001" +``` + +## Response + +On success (`response_code: "00"`): + +```json +{ + "response_code": "00", + "response_text": "Transaction completed successfully", + "description": "Success! Amount of 6500 FCFA has been transfered to ...", + "transaction_id": "TEST000001" +} +``` diff --git a/docs/psr.md b/docs/psr.md new file mode 100644 index 0000000..c26e426 --- /dev/null +++ b/docs/psr.md @@ -0,0 +1,89 @@ +# PSR — Payment Without Redirection + +The **PSR API** enables customers to pay directly on your website without being +redirected to PayDunya's payment page, using a JavaScript popup. + +## How It Works + +1. Your server creates a checkout invoice (same as PAR) and exposes an endpoint + that returns the payment token as JSON +2. Your frontend includes PayDunya's JavaScript library and a "Pay" button +3. When clicked, the JS fetches the token from your endpoint and opens a payment + popup on your site + +## Server-Side (Flask/Django/FastAPI Example) + +```python +from flask import Flask, jsonify +from paydunya import Invoice, InvoiceItem, PaydunyaClient, Store + +app = Flask(__name__) +client = PaydunyaClient( + master_key="your-master-key", + private_key="test_private_...", + token="your-token", + mode="test", +) + +@app.route("/paydunya-api") +def paydunya_api(): + store = Store(name="My Shop") + invoice = Invoice(client, store) + invoice.set_total_amount(5000) + invoice.set_description("MacBook Pro") + + result = invoice.create() + return jsonify({ + "success": True, + "mode": "test", # only in test mode + "token": result["token"], + }) +``` + +The endpoint must return JSON with `success`, `token`, and (in test mode) `mode`. + +## Client-Side (HTML/JS) + +```html + + + + + + + +``` + +## Attributes (Optional) + +On the button element: +- `data-ref` — your reference identifier for this payment +- `data-fullname` — pre-fill the payer's name +- `data-email` — pre-fill the payer's email +- `data-phone` — pre-fill the payer's phone + +## Reference + +See the full [PSR API documentation](https://developers.paydunya.com/doc/EN/psr_plugins/api_psr) for all options. diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..dfd7a00 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,33 @@ +site_name: PayDunya Python SDK +site_description: Python client for PayDunya payment services (PAR, PSR, PER, DMP) +repo_url: https://github.com/paydunyadev/paydunya-python-master +theme: + name: material + palette: + primary: indigo + features: + - navigation.sections + - content.code.copy + +nav: + - Home: index.md + - Getting Started: getting-started.md + - API Reference: + - Client: api/client.md + - Models: api/models.md + - PAR (Payment with Redirection): par.md + - PSR (Payment without Redirection): psr.md + - PER / DirectPay: per.md + - DMP (Payment Request API): dmp.md + - IPN Verification: ipn.md + +plugins: + - search + - mkdocstrings: + handlers: + python: + inventories: + - https://docs.python.org/3/objects.inv + options: + show_source: false + heading_level: 2 diff --git a/paydunya/__init__.py b/paydunya/__init__.py deleted file mode 100644 index 4b50052..0000000 --- a/paydunya/__init__.py +++ /dev/null @@ -1,156 +0,0 @@ -"""PAYDUNYA - -PAYDUNYA Python client library. -Modules implemented: DirectPay, Invoice, and OPR -""" - -__version__ = '1.0.7' -__author__ = "PAYDUNYA " - -import sys -import requests -try: - import simplejson as json -except ImportError: - import json - -# runs in LIVE mode by defaults -debug = False -api_keys = {} - -# PAYDUNYA HTTP API version -API_VERSION = 'v1' - -SERVER = "app.paydunya.com" - -# Sandbox Endpoint -SANDBOX_ENDPOINT = "https://%s/sandbox-api/%s/" % (SERVER, API_VERSION) - -# Live Endpoint -LIVE_ENDPOINT = "https://%s/api/%s/" % (SERVER, API_VERSION) - -# user-agent -PAYDUNYA_USER_AGENT = "paydunya-python/v%s" % __version__ - -# fixme: find a better way of 'self' referencing -__MODULE__ = sys.modules[__name__] - - -class PaydunyaError(Exception): - """Base Exception class""" - def __init__(self, value): - self.value = value - - def __str__(self): - return repr(self.value) - - -class Store(object): - """PAYDUNYA Store - - Creates a store object for PAYDUNYA transactions - """ - def __init__(self, **kwargs): - self.name = kwargs.get('name', None) - self.tagline = kwargs.get('tagline', None) - self.postal_address = kwargs.get('postal_address', None) - self.phone_number = kwargs.get('phone_number', None) - self.website_url = kwargs.get('website_url', None) - self.logo_url = kwargs.get('logo_url', None) - - @property - def info(self): - """Returns the store information - - What this does is simply return the store object's attributes - """ - return self.__dict__ - - -class Payment(object): - """Base class for other PAYDUNYA classes""" - - def __init__(self): - """Base class for all the other payment libraries""" - # request headers - self._headers = { - 'User-Agent': PAYDUNYA_USER_AGENT, - "Content-Type": "application/json" - } - # response object - self._response = None - # data to send to server - self._data = None - self.store = Store(name=None) - - def _process(self, resource=None, data={}): - """Processes the current transaction - - Sends an HTTP request to the PAYDUNYA API server - """ - # use object's data if no data is passed - _data = data or self._data - rsc_url = self.get_rsc_endpoint(resource) - if _data: - req = requests.post(rsc_url, data=json.dumps(_data), - headers=self.headers) - else: - req = requests.get(rsc_url, params=_data, - headers=self.headers) - if req.status_code == 200: - self._response = json.loads(req.text) - if int(self._response['response_code']) == 00: - return (True, self._response) - else: - return (False, self._response['response_text']) - else: - return (500, "Request Failed") - - @property - def headers(self): - """Returns the client's Request headers""" - return dict(self._config, **self._headers) - - def add_header(self, header): - """Add a custom HTTP header to the client's request headers""" - if type(header) is dict: - self._headers.update(header) - else: - raise ValueError( - "Dictionary expected, got '%s' instead" % type(header) - ) - - def get_rsc_endpoint(self, rsc): - """Returns the HTTP API URL for current payment transaction""" - if self.debug: - return SANDBOX_ENDPOINT + rsc - return LIVE_ENDPOINT + rsc - - @property - def debug(self): - """Returns the current transaction mode""" - return __MODULE__.debug - - @property - def _config(self): - _m = __MODULE__ - return { - 'PAYDUNYA-MASTER-KEY': _m.api_keys.get('PAYDUNYA-MASTER-KEY'), - 'PAYDUNYA-PRIVATE-KEY': _m.api_keys.get('PAYDUNYA-PRIVATE-KEY'), - 'PAYDUNYA-TOKEN': _m.api_keys.get('PAYDUNYA-TOKEN') - } - - -# moved here so the modules that depend on the 'Payment' class will work -from .invoice import Invoice, InvoiceItem -from .direct_payments import DirectPay -from .opr import OPR - -__all__ = [ - Store.__name__, - Payment.__name__, - Invoice.__name__, - InvoiceItem.__name__, - DirectPay.__name__, - OPR.__name__ -] diff --git a/paydunya/direct_payments.py b/paydunya/direct_payments.py deleted file mode 100644 index 79b6d31..0000000 --- a/paydunya/direct_payments.py +++ /dev/null @@ -1,23 +0,0 @@ -"""PAYDUNYA DirectPay""" -from . import Payment - -class DirectPay(Payment): - """Directpay processing class - - Receipient account_info format: - '{ - "account_alias" : "774563209", - "amount" : 215000 - }' - """ - def __init__(self, account_alias=None, amount=None): - self.transaction = { - 'account_alias': account_alias, - 'amount': amount - } - super(DirectPay, self).__init__() - - def process(self, transaction=None): - """Process the transaction""" - return self._process('direct-pay/credit-account', - transaction or self.transaction) diff --git a/paydunya/invoice.py b/paydunya/invoice.py deleted file mode 100644 index 92911f3..0000000 --- a/paydunya/invoice.py +++ /dev/null @@ -1,131 +0,0 @@ -"""PAYDUNYA Invoice""" -from . import Payment -from collections import namedtuple - -InvoiceItem = namedtuple('InvoiceItem', 'name quantity unit_price \ - total_price description') - - -class Invoice(Payment): - """Payment invoice""" - - def __init__(self, store=None): - """Create an invoice - - Accepts list of store object as initial parameter and - a dictionary of tokens for accessing the PAYDUNYA API - """ - self.cancel_url = None - self.return_url = None - self.callback_url = None - self.description = None - self.items = {} - self.total_amount = 0 - self.custom_data = {} - self.taxes = {} - self.channels = [] - super(Invoice, self).__init__() - if store: - self.store = store - - def create(self, items=[], taxes=[], custom_data=[]): - """Adds the items to the invoice - - Format of 'items': - [ - InvoiceItem( - name="VIP Ticket", - quantity= 2, - unit_price= "3500", - total_price= "7000", - description= "VIP Tickets for the Party" - } - ,... - ] - """ - self.add_items(items) - self.add_taxes(taxes) - self.add_custom_data(custom_data) - return self._process('checkout-invoice/create', self._prepare_data) - - def confirm(self, token=None): - """Returns the status of the invoice - - STATUSES: pending, completed, cancelled - """ - _token = token if token else self._response.get("token") - return self._process('checkout-invoice/confirm/' + str(_token)) - - def add_taxes(self, taxes): - """Appends the data to the 'taxes' key in the request object - - 'taxes' should be in format: [("tax_name", "tax_amount")] - For example: - [("Other TAX", 700), ("VAT", 5000)] - """ - # fixme: how to resolve duplicate tax names - _idx = len(self.taxes) # current index to prevent overwriting - for idx, tax in enumerate(taxes): - tax_key = "tax_" + str(idx + _idx) - self.taxes[tax_key] = {"name": tax[0], "amount": tax[1]} - - def add_custom_data(self, data=[]): - """Adds the data to teh custom data sent to the server - - data format: [("phone_brand", Motorola V3"), ("model", "65456AH23")] - """ - self.custom_data.update(dict(data)) - - def add_item(self, item): - """Updates the list of items in the current transaction""" - _idx = len(self.items) - self.items.update({"item_" + str(_idx + 1): item}) - - def add_items(self, items): - for item in items: - self.add_item(item) - - def add_channel(self, channel): - """Updates the list of payment channels in the current transaction""" - self.channels.append(channel) - - def add_channels(self, channels): - for channel in channels: - self.add_channel(channel) - - @property - def _prepare_data(self): - """Formats the data in the current transaction for processing""" - total_amount = self.total_amount or self.calculate_total_amt() - self._data = { - "invoice": { - "items": self.__encode_items(self.items), - "taxes": self.taxes, - "total_amount": total_amount, - "description": self.description, - "channels": self.channels - }, - "store": self.store.info, - "custom_data": self.custom_data, - "actions": { - "cancel_url": self.cancel_url, - "return_url": self.return_url, - "callback_url": self.callback_url - } - } - return self._data - - def calculate_total_amt(self, items={}): - """Returns the total amount/cost of items in the current invoice""" - _items = items.items() or self.items.items() - return sum(float(x[1].total_price) for x in _items) - - def __encode_items(self, items): - """Encodes the InvoiceItems into a JSON serializable format - - items = [('item_1',InvoiceItem(name='VIP Ticket', quantity=2, - unit_price='3500', total_price='7000', - description='VIP Tickets for party')),...] - """ - xs = [item._asdict() for (_key, item) in items.items()] - return list(map(lambda x: dict(zip(x.keys(), x.values())), xs)) diff --git a/paydunya/opr.py b/paydunya/opr.py deleted file mode 100644 index ae127ae..0000000 --- a/paydunya/opr.py +++ /dev/null @@ -1,45 +0,0 @@ -"""PAYDUNYA Onsite Payments Request""" -from . import Payment - - -class OPR(Payment): - """Onsite Payment Request""" - def __init__(self, data={}, store=None): - self._opr_data = self._build_opr_data(data, store) - super(OPR, self).__init__() - if store: - self.store = store - - def _build_opr_data(self, data, store): - """Returns a well formatted OPR data""" - return { - "invoice_data": { - "invoice": { - "total_amount": data.get("total_amount"), - "description": data.get("description") - }, - "store": store.info - }, - "opr_data": { - "account_alias": data.get("account_alias") - } - } - - def create(self, data={}, store=None): - """Initiazes an OPR - - First step in the OPR process is to create the OPR request. - Returns the OPR token - """ - _store = store or self.store - _data = self._build_opr_data(data, _store) if data else self._opr_data - return self._process('opr/create', _data) - - def charge(self, data): - """Second stage of an OPR request""" - token = data.get("token", self._response["token"]) - data = { - "token": token, - "confirm_token": data.get("confirm_token") - } - return self._process('opr/charge', data) diff --git a/pyproject.toml b/pyproject.toml index b5a3c46..823940f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,88 @@ [build-system] -requires = [ - "setuptools>=42", - "wheel" +requires = ["hatchling>=1.21"] +build-backend = "hatchling.build" + +[project] +name = "paydunya" +version = "2.0.0" +description = "PayDunya Python client library — mobile money payment integration" +readme = "README.md" +license = { file = "LICENSE.txt" } +authors = [{ name = "PAYDUNYA", email = "paydunya@paydunya.com" }] +keywords = ["paydunya", "payment", "mobile-money", "africa"] +requires-python = ">=3.10" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Office/Business :: Financial :: Point-Of-Sale", ] -build-backend = "setuptools.build_meta" \ No newline at end of file +dependencies = [ + "httpx>=0.27", +] + +[project.urls] +Homepage = "https://developers.paydunya.com/" +Documentation = "https://developers.paydunya.com/doc/EN/introduction" +Repository = "https://github.com/paydunyadev/paydunya-python-master" +Issues = "https://github.com/paydunyadev/paydunya-python-master/issues" + +[dependency-groups] +dev = [ + "mkdocs-material>=9.5", + "mkdocstrings[python]>=0.25", + "pre-commit>=3.7", + "pytest>=8.2", + "pytest-cov>=5.0", + "pytest-httpx>=0.30", + "ruff>=0.5", + "tox>=4.15", + "tox-uv>=1.11", +] +docs = [ + "mkdocs-material>=9.5", + "mkdocstrings[python]>=0.25", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/paydunya"] + +[tool.hatch.build.targets.sdist] +include = ["src/", "docs/", "tests/", "README.md", "CHANGELOG.md", "LICENSE.txt", "pyproject.toml"] + +[tool.ruff] +target-version = "py310" +line-length = 100 + +[tool.ruff.lint] +select = ["E", "F", "I", "UP", "B", "SIM", "RUF", "W"] +ignore = ["B008"] + +[tool.ruff.lint.isort] +force-single-line = true + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" + +[tool.pytest.ini_options] +testpaths = ["tests"] +python_files = "test_*.py" +addopts = ["--strict-markers", "-ra"] + +[tool.coverage.run] +source = ["paydunya"] +branch = true + +[tool.coverage.report] +exclude_also = [ + "if TYPE_CHECKING:", + "@abstractmethod", + "raise NotImplementedError", +] +fail_under = 85 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1f2902e..0000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -flake8==4.0.1 -mccabe==0.6.1 -pep8==1.7.1 -pyflakes==2.4.0 -requests==2.27.1 -wheel==0.37.1 diff --git a/runtests.py b/runtests.py deleted file mode 100644 index eb99bee..0000000 --- a/runtests.py +++ /dev/null @@ -1,2287 +0,0 @@ -#! /usr/bin/env python - -sources = """ -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 -xf9s0v8DJbu0uw== -""" - -import sys -import base64 -import zlib -import imp - -class DictImporter(object): - def __init__(self, sources): - self.sources = sources - - def find_module(self, fullname, path=None): - if fullname in self.sources: - return self - if fullname+'.__init__' in self.sources: - return self - return None - - def load_module(self, fullname): - # print "load_module:", fullname - from types import ModuleType - try: - s = self.sources[fullname] - is_pkg = False - except KeyError: - s = self.sources[fullname+'.__init__'] - is_pkg = True - - co = compile(s, fullname, 'exec') - module = sys.modules.setdefault(fullname, ModuleType(fullname)) - module.__file__ = "%s/%s" % (__file__, fullname) - module.__loader__ = self - if is_pkg: - module.__path__ = [fullname] - - do_exec(co, module.__dict__) - return sys.modules[fullname] - - def get_source(self, name): - res = self.sources.get(name) - if res is None: - res = self.sources.get(name+'.__init__') - return res - -if __name__ == "__main__": - if sys.version_info >= (3,0): - exec("def do_exec(co, loc): exec(co, loc)\n") - import pickle - sources = sources.encode("ascii") # ensure bytes - sources = pickle.loads(zlib.decompress(base64.decodebytes(sources))) - else: - import cPickle as pickle - exec("def do_exec(co, loc): exec co in loc\n") - sources = pickle.loads(zlib.decompress(base64.decodestring(sources))) - - importer = DictImporter(sources) - sys.meta_path.append(importer) - - import py - py.cmdline.pytest() diff --git a/setup.py b/setup.py deleted file mode 100644 index 3d751f1..0000000 --- a/setup.py +++ /dev/null @@ -1,88 +0,0 @@ -from setuptools import setup, Command -from unittest import TextTestRunner, TestLoader -from glob import glob -from os.path import splitext, basename, join as pjoin -try: - from os.path import walk -except ImportError: - from os import walk -import os - - -class TestCommand(Command): - user_options = [] - - def initialize_options(self): - self._dir = os.getcwd() - - def finalize_options(self): - pass - - def run(self): - ''' - Finds all the tests modules in tests/, and runs them. - ''' - testfiles = [] - for t in glob(pjoin(self._dir, 'tests', '*.py')): - if not t.endswith('__init__.py'): - testfiles.append('.'.join( - ['tests', splitext(basename(t))[0]]) - ) - import sys - ROOT = os.path.dirname(os.getcwd()) - PAYDUNYA_LIBS = os.path.join(ROOT, "paydunya") - sys.path.append(PAYDUNYA_LIBS) - tests = TestLoader().loadTestsFromNames(testfiles) - t = TextTestRunner(verbosity=1) - t.run(tests) - - -class CleanCommand(Command): - """Recursively Delete all compile python modules""" - user_options = [] - - def initialize_options(self): - self._clean_me = [] - for root, dirs, files in os.walk('.'): - for f in files: - if f.endswith('.pyc'): - self._clean_me.append(pjoin(root, f)) - - def finalize_options(self): - pass - - def run(self): - for clean_me in self._clean_me: - try: - os.unlink(clean_me) - except: - pass - - -def readme(filename='README.rst'): - with open('README.rst') as f: - text = f.read() - f.close() - return text - -setup( - name='paydunya', - version="1.0.7", - author='PAYDUNYA', - author_email='paydunya@paydunya.com', - packages=['paydunya'], - cmdclass={'test': TestCommand, 'clean': CleanCommand}, - scripts=[], - url='https://github.com/paydunyadev/paydunya-python-master', - license='LICENSE.txt', - keywords="paydunya mobile money payments", - description='PAYDUNYA Python client library', - long_description=readme('README.rst'), - classifiers=[ - "Development Status :: 2 - Pre-Alpha", - "Intended Audience :: Developers", - "Topic :: Utilities", - "License :: OSI Approved :: MIT License", - ], - install_requires=['requests >=2.0'], -) diff --git a/src/paydunya/__init__.py b/src/paydunya/__init__.py new file mode 100644 index 0000000..55190ba --- /dev/null +++ b/src/paydunya/__init__.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +from paydunya.client import PaydunyaClient +from paydunya.direct_pay import DirectPay +from paydunya.dmp import DMP +from paydunya.exceptions import APIError +from paydunya.exceptions import AuthenticationError +from paydunya.exceptions import DMPError +from paydunya.exceptions import PaydunyaError +from paydunya.invoice import Invoice +from paydunya.ipn import verify_ipn_hash +from paydunya.models import Actions +from paydunya.models import Customer +from paydunya.models import InvoiceItem +from paydunya.models import Store +from paydunya.models import Tax + +__version__ = "2.0.0" +__all__ = [ + "DMP", + "APIError", + "Actions", + "AuthenticationError", + "Customer", + "DMPError", + "DirectPay", + "Invoice", + "InvoiceItem", + "PaydunyaClient", + "PaydunyaError", + "Store", + "Tax", + "verify_ipn_hash", +] diff --git a/src/paydunya/client.py b/src/paydunya/client.py new file mode 100644 index 0000000..9e9e699 --- /dev/null +++ b/src/paydunya/client.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +from typing import Any + +import httpx + +from paydunya.exceptions import APIError +from paydunya.exceptions import AuthenticationError +from paydunya.exceptions import PaydunyaError + +TEST_BASE = "https://app.paydunya.com/sandbox-api/v1" +LIVE_BASE = "https://app.paydunya.com/api/v1" +DMP_BASE = "https://app.paydunya.com/api/v1" + + +class PaydunyaClient: + def __init__( + self, + master_key: str, + private_key: str, + token: str, + *, + mode: str = "live", + timeout: float = 30.0, + transport: httpx.BaseTransport | None = None, + ) -> None: + if mode not in ("test", "live"): + raise ValueError("mode must be 'test' or 'live'") + + self.master_key = master_key + self.private_key = private_key + self.token = token + self.mode = mode + self.timeout = timeout + + self._headers = { + "PAYDUNYA-MASTER-KEY": master_key, + "PAYDUNYA-PRIVATE-KEY": private_key, + "PAYDUNYA-TOKEN": token, + "Content-Type": "application/json", + "User-Agent": "paydunya-python/2.0", + } + + self._transport = transport or httpx.HTTPTransport() + self._http = httpx.Client( + base_url=LIVE_BASE, + headers=self._headers, + timeout=httpx.Timeout(timeout), + transport=self._transport, + ) + + def _resolve_url(self, path: str, use_sandbox: bool = False) -> str: + base = TEST_BASE if use_sandbox else LIVE_BASE + return f"{base}/{path.lstrip('/')}" + + def _handle_response(self, response: httpx.Response) -> dict[str, Any]: + if response.status_code != 200: + raise PaydunyaError(f"HTTP {response.status_code}: {response.text}") + + try: + data: dict[str, Any] = response.json() + except ValueError: + return {"raw": response.text} + + response_code = data.get("response_code") or data.get("response-code") + + if response_code is not None and response_code != "00": + message = data.get("response_text", data.get("message", "Unknown error")) + if response_code in ("1000", "4000"): + raise AuthenticationError(response_code, message) + raise APIError(response_code, message) + + return data + + def _send(self, method: str, path: str, json: dict[str, Any] | None = None) -> dict[str, Any]: + use_sandbox = self.mode == "test" and "dmp" not in path + url = self._resolve_url(path, use_sandbox=use_sandbox) + try: + response = self._http.request(method, url, json=json) + except httpx.RequestError as exc: + raise PaydunyaError(f"HTTP request failed: {exc}") from exc + return self._handle_response(response) + + def post(self, path: str, data: dict[str, Any] | None = None) -> dict[str, Any]: + return self._send("POST", path, json=data) + + def get(self, path: str) -> dict[str, Any]: + return self._send("GET", path) + + def dmp_post(self, path: str, data: dict[str, Any] | None = None) -> dict[str, Any]: + url = f"{DMP_BASE}/{path.lstrip('/')}" + try: + response = self._http.post(url, json=data) + except httpx.RequestError as exc: + raise PaydunyaError(f"HTTP request failed: {exc}") from exc + return self._handle_response(response) + + def close(self) -> None: + self._http.close() diff --git a/src/paydunya/direct_pay.py b/src/paydunya/direct_pay.py new file mode 100644 index 0000000..029f02f --- /dev/null +++ b/src/paydunya/direct_pay.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +from paydunya.client import PaydunyaClient + + +class DirectPay: + def __init__(self, client: PaydunyaClient) -> None: + self._client = client + + def pay(self, account_alias: str, amount: float | int) -> dict: + return self._client.post( + "direct-pay/credit-account", + {"account_alias": account_alias, "amount": amount}, + ) diff --git a/src/paydunya/dmp.py b/src/paydunya/dmp.py new file mode 100644 index 0000000..7d4dda0 --- /dev/null +++ b/src/paydunya/dmp.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +from paydunya.client import PaydunyaClient +from paydunya.exceptions import APIError + + +class DMP: + def __init__(self, client: PaydunyaClient) -> None: + self._client = client + + def create( + self, + amount: float | int, + *, + recipient_email: str | None = None, + recipient_phone: str | None = None, + support_fees: bool = False, + send_notification: bool = True, + ) -> dict: + if amount < 200 or amount > 3_000_000: + raise APIError("4000", "amount must be between 200 and 3,000,000") + + if not recipient_email and not recipient_phone: + raise APIError("4000", "recipient_email or recipient_phone is required") + + payload: dict = { + "amount": amount, + "support_fees": 1 if support_fees else 0, + "send_notification": 1 if send_notification else 0, + } + if recipient_email: + payload["recipient_email"] = recipient_email + if recipient_phone: + payload["recipient_phone"] = recipient_phone + + return self._client.dmp_post("dmp-api", payload) + + def check_status(self, reference_number: str) -> dict: + return self._client.dmp_post("dmp-api/check-status", {"reference_number": reference_number}) diff --git a/src/paydunya/exceptions.py b/src/paydunya/exceptions.py new file mode 100644 index 0000000..e2ac978 --- /dev/null +++ b/src/paydunya/exceptions.py @@ -0,0 +1,19 @@ +class PaydunyaError(Exception): + """Base exception for the PayDunya SDK.""" + + +class APIError(PaydunyaError): + """Raised when the PayDunya API returns a non-success response.""" + + def __init__(self, response_code: str, message: str) -> None: + self.response_code = response_code + self.message = message + super().__init__(f"[{response_code}] {message}") + + +class AuthenticationError(APIError): + """Raised when API keys are missing or invalid (error code 1000 or 4000).""" + + +class DMPError(APIError): + """Raised for DMP-specific API errors.""" diff --git a/src/paydunya/invoice.py b/src/paydunya/invoice.py new file mode 100644 index 0000000..6d5a8b8 --- /dev/null +++ b/src/paydunya/invoice.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +from typing import Any + +from paydunya.client import PaydunyaClient +from paydunya.models import Actions +from paydunya.models import Customer +from paydunya.models import InvoiceItem +from paydunya.models import Store +from paydunya.models import Tax + + +class Invoice: + def __init__( + self, + client: PaydunyaClient, + store: Store | None = None, + ) -> None: + self._client = client + self.store = store or Store(name="") + + self.items: list[InvoiceItem] = [] + self.taxes: list[Tax] = [] + self.customer = Customer() + self.channels: list[str] = [] + self.actions = Actions() + + self.total_amount: float = 0 + self.description: str = "" + self.custom_data: dict[str, Any] = {} + + def set_total_amount(self, amount: float) -> None: + self.total_amount = amount + + def set_description(self, description: str) -> None: + self.description = description + + def set_cancel_url(self, url: str) -> None: + self.actions.cancel_url = url + + def set_return_url(self, url: str) -> None: + self.actions.return_url = url + + def set_callback_url(self, url: str) -> None: + self.actions.callback_url = url + + def set_customer(self, name: str = "", email: str = "", phone: str = "") -> None: + self.customer = Customer(name=name, email=email, phone=phone) + + def add_item(self, item: InvoiceItem) -> None: + self.items.append(item) + + def add_items(self, items: list[InvoiceItem]) -> None: + self.items.extend(items) + + def add_tax(self, name: str, amount: float | int) -> None: + self.taxes.append(Tax(name=name, amount=amount)) + + def add_custom_data(self, data: dict[str, Any]) -> None: + self.custom_data.update(data) + + def add_channel(self, channel: str) -> None: + self.channels.append(channel) + + def add_channels(self, channels: list[str]) -> None: + self.channels.extend(channels) + + def calculate_total(self) -> float: + return sum(float(item.total_price) for item in self.items) + + def _build_payload(self) -> dict[str, Any]: + total = self.total_amount or self.calculate_total() + + items_dict: dict[str, Any] = {} + for idx, item in enumerate(self.items): + items_dict[f"item_{idx}"] = item.asdict() + + taxes_dict: dict[str, Any] = {} + for idx, tax in enumerate(self.taxes): + taxes_dict[f"tax_{idx}"] = tax.asdict() + + invoice_data: dict[str, Any] = { + "total_amount": total, + "description": self.description, + } + + if items_dict: + invoice_data["items"] = items_dict + if taxes_dict: + invoice_data["taxes"] = taxes_dict + if self.channels: + invoice_data["channels"] = self.channels + + customer_data = self.customer.asdict() + if customer_data: + invoice_data["customer"] = customer_data + + payload: dict[str, Any] = { + "invoice": invoice_data, + "store": self.store.asdict(), + } + + if self.custom_data: + payload["custom_data"] = self.custom_data + + actions_data = self.actions.asdict() + if actions_data: + payload["actions"] = actions_data + + return payload + + def create(self) -> dict[str, Any]: + payload = self._build_payload() + return self._client.post("checkout-invoice/create", payload) + + def confirm(self, token: str) -> dict[str, Any]: + return self._client.get(f"checkout-invoice/confirm/{token}") diff --git a/src/paydunya/ipn.py b/src/paydunya/ipn.py new file mode 100644 index 0000000..aaca50b --- /dev/null +++ b/src/paydunya/ipn.py @@ -0,0 +1,9 @@ +from __future__ import annotations + +import hashlib +import hmac + + +def verify_ipn_hash(master_key: str, received_hash: str) -> bool: + computed = hashlib.sha512(master_key.encode()).hexdigest() + return hmac.compare_digest(computed, received_hash) diff --git a/src/paydunya/models.py b/src/paydunya/models.py new file mode 100644 index 0000000..f9128b4 --- /dev/null +++ b/src/paydunya/models.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + + +@dataclass +class Customer: + name: str = "" + email: str = "" + phone: str = "" + + def asdict(self) -> dict[str, str]: + return {k: v for k, v in self.__dict__.items() if v} + + +@dataclass +class Store: + name: str + tagline: str = "" + postal_address: str = "" + phone_number: str = "" + website_url: str = "" + logo_url: str = "" + + def asdict(self) -> dict[str, str]: + return {k: v for k, v in self.__dict__.items() if v} + + +@dataclass +class InvoiceItem: + name: str + quantity: int + unit_price: str + total_price: str + description: str = "" + + def asdict(self) -> dict[str, str]: + return { + "name": self.name, + "quantity": str(self.quantity), + "unit_price": self.unit_price, + "total_price": self.total_price, + "description": self.description, + } + + +@dataclass +class Actions: + cancel_url: str = "" + return_url: str = "" + callback_url: str = "" + + def asdict(self) -> dict[str, str]: + return {k: v for k, v in self.__dict__.items() if v} + + +@dataclass +class Tax: + name: str + amount: float | int + + def asdict(self) -> dict[str, Any]: + return {"name": self.name, "amount": self.amount} diff --git a/src/paydunya/py.typed b/src/paydunya/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 18ab8da..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# access keys -PAYDUNYA_ACCESS_TOKENS = { - 'PAYDUNYA-MASTER-KEY': "5b9f531a-fbb8-487a-8045-3b4c7ac5acee", - 'PAYDUNYA-PRIVATE-KEY': "test_private_oGslgmzSNL3RSkjlsnPOsZZg9IA", - 'PAYDUNYA-TOKEN': "ff1d576409b2587cc1c2" -} diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..af5af10 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import pytest + +from paydunya.client import PaydunyaClient + + +@pytest.fixture +def fake_keys() -> dict[str, str]: + return { + "master_key": "test-master-key-12345", + "private_key": "test_private_abcdef67890", + "token": "test-token-112233", + } + + +@pytest.fixture +def client_test(fake_keys: dict[str, str]) -> PaydunyaClient: + return PaydunyaClient(**fake_keys, mode="test") + + +@pytest.fixture +def client_live(fake_keys: dict[str, str]) -> PaydunyaClient: + return PaydunyaClient(**fake_keys, mode="live") + + +@pytest.fixture +def mock_http(httpx_mock): + return httpx_mock diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 0000000..0a6a6c7 --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +import pytest + +from paydunya.client import DMP_BASE +from paydunya.client import LIVE_BASE +from paydunya.client import TEST_BASE +from paydunya.client import PaydunyaClient + + +def test_test_mode_uses_sandbox_endpoint(fake_keys, mock_http): + client = PaydunyaClient(**fake_keys, mode="test") + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/test", + json={"response_code": "00"}, + ) + client.post("test") + assert mock_http.get_requests()[0].url.path.startswith("/sandbox-api") + + +def test_live_mode_uses_live_endpoint(fake_keys, mock_http): + client = PaydunyaClient(**fake_keys, mode="live") + mock_http.add_response( + method="POST", + url=f"{LIVE_BASE}/test", + json={"response_code": "00"}, + ) + client.post("test") + assert mock_http.get_requests()[0].url.path.startswith("/api/v1") + + +def test_mode_must_be_valid(fake_keys): + with pytest.raises(ValueError, match="mode"): + PaydunyaClient(**fake_keys, mode="invalid") + + +def test_headers_include_auth_keys(fake_keys, mock_http): + client = PaydunyaClient(**fake_keys, mode="test") + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/test", + json={"response_code": "00", "response_text": "OK"}, + ) + resp = client.post("test", {"foo": "bar"}) + assert resp["response_code"] == "00" + assert len(mock_http.get_requests()) == 1 + req = mock_http.get_requests()[0] + assert req.headers["PAYDUNYA-MASTER-KEY"] == fake_keys["master_key"] + assert req.headers["Content-Type"] == "application/json" + + +def test_non_200_response_raises(fake_keys, mock_http): + client = PaydunyaClient(**fake_keys, mode="test") + mock_http.add_response(method="POST", url=f"{TEST_BASE}/fail", status_code=500) + from paydunya.exceptions import PaydunyaError + + with pytest.raises(PaydunyaError, match="500"): + client.post("fail") + + +def test_response_code_not_00_raises(fake_keys, mock_http): + client = PaydunyaClient(**fake_keys, mode="test") + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/error", + json={"response_code": "4000", "response_text": "Missing keys"}, + ) + from paydunya.exceptions import APIError + + with pytest.raises(APIError, match="4000"): + client.post("error") + + +def test_response_code_1000_raises_authentication_error(fake_keys, mock_http): + client = PaydunyaClient(**fake_keys, mode="test") + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/auth", + json={"response_code": "1000", "response_text": "Invalid keys"}, + ) + from paydunya.exceptions import AuthenticationError + + with pytest.raises(AuthenticationError, match="1000"): + client.post("auth") + + +def test_dmp_post_uses_dmp_base(fake_keys, mock_http): + client = PaydunyaClient(**fake_keys, mode="live") + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api", + json={"response-code": "00", "message": "OK"}, + ) + resp = client.dmp_post("dmp-api", {"amount": 500}) + assert resp["response-code"] == "00" + + +def test_dmp_post_error_code(fake_keys, mock_http): + client = PaydunyaClient(**fake_keys, mode="live") + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api", + json={"response-code": "4004", "message": "Not found"}, + ) + from paydunya.exceptions import APIError + + with pytest.raises(APIError, match="4004"): + client.dmp_post("dmp-api", {"reference_number": "bad"}) + + +def test_client_close(fake_keys): + client = PaydunyaClient(**fake_keys) + client.close() + assert client._http.is_closed diff --git a/tests/test_compat.py b/tests/test_compat.py new file mode 100644 index 0000000..0db0e54 --- /dev/null +++ b/tests/test_compat.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +import json + +from paydunya import Invoice +from paydunya import InvoiceItem +from paydunya import Store +from paydunya.client import TEST_BASE + + +def test_invoice_with_module_level_api(client_test, mock_http): + store = Store(name="Test Store") + items = [ + InvoiceItem( + name="Croco shoes", + quantity=3, + unit_price="10000", + total_price="30000", + description="Shoes", + ) + ] + invoice = Invoice(client_test, store) + invoice.add_items(items) + invoice.set_total_amount(30000) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={ + "response_code": "00", + "response_text": "OK", + "token": "test_token_abc", + }, + ) + + resp = invoice.create() + assert resp["response_code"] == "00" + assert resp["token"] == "test_token_abc" + + +def test_taxes_via_add_tax(client_test, mock_http): + store = Store(name="Test Store") + invoice = Invoice(client_test, store) + invoice.set_total_amount(10000) + invoice.add_tax("TVA (18%)", 1800) + invoice.add_tax("Livraison", 1000) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + taxes = payload["invoice"]["taxes"] + assert taxes["tax_0"]["name"] == "TVA (18%)" + assert taxes["tax_1"]["name"] == "Livraison" + + +def test_store_asdict_in_payload(client_test, mock_http): + store = Store( + name="Sandra's Store", + tagline="Elegance is priceless", + phone_number="336530583", + ) + invoice = Invoice(client_test, store) + invoice.set_total_amount(1000) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert payload["store"]["name"] == "Sandra's Store" + assert payload["store"]["tagline"] == "Elegance is priceless" + assert payload["store"]["phone_number"] == "336530583" + + +def test_model_dataclasses(): + from paydunya.models import Actions + from paydunya.models import Customer + from paydunya.models import InvoiceItem + from paydunya.models import Store + from paydunya.models import Tax + + item = InvoiceItem(name="X", quantity=1, unit_price="10", total_price="10") + assert item.asdict()["quantity"] == "1" + + customer = Customer(name="John") + assert customer.asdict()["name"] == "John" + assert "email" not in customer.asdict() + + store = Store(name="Shop") + assert store.asdict() == {"name": "Shop"} + + tax = Tax(name="VAT", amount=18) + assert tax.asdict()["amount"] == 18 + + actions = Actions() + assert actions.asdict() == {} diff --git a/tests/test_direct_pay.py b/tests/test_direct_pay.py new file mode 100644 index 0000000..5dc0499 --- /dev/null +++ b/tests/test_direct_pay.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +import json + +from paydunya.client import TEST_BASE +from paydunya.direct_pay import DirectPay + + +def test_direct_pay_posts_correct_payload(client_test, mock_http): + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/direct-pay/credit-account", + json={ + "response_code": "00", + "response_text": "Transaction completed successfully", + "transaction_id": "TEST000001", + }, + ) + + dp = DirectPay(client_test) + resp = dp.pay(account_alias="774563209", amount=4500) + + assert resp["transaction_id"] == "TEST000001" + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + assert payload["account_alias"] == "774563209" + assert payload["amount"] == 4500 diff --git a/tests/test_dmp.py b/tests/test_dmp.py new file mode 100644 index 0000000..b01a18a --- /dev/null +++ b/tests/test_dmp.py @@ -0,0 +1,145 @@ +from __future__ import annotations + +import json + +import pytest + +from paydunya.client import DMP_BASE +from paydunya.dmp import DMP +from paydunya.exceptions import APIError + + +class TestDMP: + def test_create_minimal(self, client_test, mock_http): + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api", + json={"response-code": "00", "message": "Payment request created"}, + ) + + dmp = DMP(client_test) + resp = dmp.create(amount=1250, recipient_email="test@example.com") + + assert resp["response-code"] == "00" + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + assert payload["amount"] == 1250 + assert payload["recipient_email"] == "test@example.com" + assert payload["support_fees"] == 0 + assert payload["send_notification"] == 1 + + def test_create_with_phone(self, client_test, mock_http): + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api", + json={"response-code": "00", "message": "OK"}, + ) + + dmp = DMP(client_test) + resp = dmp.create(amount=500, recipient_phone="771234567") + + assert resp["response-code"] == "00" + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + assert payload["recipient_phone"] == "771234567" + + def test_create_with_both_email_and_phone(self, client_test, mock_http): + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api", + json={"response-code": "00", "message": "OK"}, + ) + + dmp = DMP(client_test) + dmp.create( + amount=1000, + recipient_email="test@example.com", + recipient_phone="771234567", + ) + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + assert "recipient_email" in payload + assert "recipient_phone" in payload + + def test_create_with_support_fees(self, client_test, mock_http): + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api", + json={"response-code": "00"}, + ) + + dmp = DMP(client_test) + dmp.create(amount=1000, recipient_email="a@b.com", support_fees=True) + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + assert payload["support_fees"] == 1 + + def test_create_no_notification(self, client_test, mock_http): + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api", + json={ + "response-code": "00", + "reference_number": "4190239470044", + "url": "https://pydu.me/k5Rrrj", + "description": "Payment request created successfully", + }, + ) + + dmp = DMP(client_test) + resp = dmp.create( + amount=1250, + recipient_email="test@example.com", + send_notification=False, + ) + + assert resp["reference_number"] == "4190239470044" + assert resp["url"] == "https://pydu.me/k5Rrrj" + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + assert payload["send_notification"] == 0 + + def test_amount_below_minimum(self, client_test): + dmp = DMP(client_test) + with pytest.raises(APIError, match="between 200"): + dmp.create(amount=50, recipient_email="a@b.com") + + def test_amount_above_maximum(self, client_test): + dmp = DMP(client_test) + with pytest.raises(APIError, match="between 200"): + dmp.create(amount=5_000_000, recipient_email="a@b.com") + + def test_no_recipient(self, client_test): + dmp = DMP(client_test) + with pytest.raises(APIError, match="recipient"): + dmp.create(amount=500) + + def test_check_status(self, client_test, mock_http): + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api/check-status", + json={"response-code": "00", "status": "completed"}, + ) + + dmp = DMP(client_test) + resp = dmp.check_status("4190239470044") + + assert resp["status"] == "completed" + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + assert payload["reference_number"] == "4190239470044" + + def test_api_error_4004(self, client_test, mock_http): + mock_http.add_response( + method="POST", + url=f"{DMP_BASE}/dmp-api", + json={"response-code": "4004", "message": "Payment request not found"}, + ) + + dmp = DMP(client_test) + with pytest.raises(APIError, match="4004"): + dmp.create(amount=500, recipient_email="a@b.com") diff --git a/tests/test_general.py b/tests/test_general.py deleted file mode 100644 index ee4f14c..0000000 --- a/tests/test_general.py +++ /dev/null @@ -1,37 +0,0 @@ -import unittest -import paydunya -from . import PAYDUNYA_ACCESS_TOKENS - -paydunya.debug = True -paydunya.api_keys = PAYDUNYA_ACCESS_TOKENS - - -class TestGeneral(unittest.TestCase): - """General/Miscellaneous tests""" - def setUp(self): - # Your PAYDUNYA developer tokens - self.store = paydunya.Store(name="Fabrice Accessoires") - self.opr_data = {'total_amount': 215000, - 'description': "Samsung Galaxy S6", - "account_alias": "774563209"} - self.opr = paydunya.OPR(self.opr_data, self.store) - - def tearDown(self): - self.opr = None - self.store = None - self.opr_data = None - - def test_rsc_endpoints(self): - endpoint = 'checkout-invoice/confirm/test_98567JGF' - url = self.opr.get_rsc_endpoint(endpoint) - self.assertTrue(url.startswith('https') and url.endswith(endpoint)) - - def test_add_headers(self): - header = {'Foo': 'Bar'} - self.opr.add_header(header) - self.assertTrue("Foo" in self.opr.headers.keys()) - self.assertFalse('FooBar' in self.opr.headers.keys()) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 0000000..b4b7d72 --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,7 @@ +from __future__ import annotations + +from paydunya import __version__ + + +def test_version(): + assert __version__ == "2.0.0" diff --git a/tests/test_invoice.py b/tests/test_invoice.py index d5224fe..46ddbe6 100644 --- a/tests/test_invoice.py +++ b/tests/test_invoice.py @@ -1,50 +1,273 @@ -import unittest -import paydunya -from . import PAYDUNYA_ACCESS_TOKENS +from __future__ import annotations -paydunya.debug = True -paydunya.api_keys = PAYDUNYA_ACCESS_TOKENS +import json +from paydunya.client import TEST_BASE +from paydunya.invoice import Invoice +from paydunya.models import InvoiceItem +from paydunya.models import Store -class Invoice(unittest.TestCase): - def setUp(self): - unittest.TestCase.setUp(self) - self.store = paydunya.Store(name="Event Shop") - self.items = [ - paydunya.InvoiceItem( - name="VIP Ticket", + +class TestInvoicePayload: + def test_items_are_keyed_as_item_0(self, client_test, mock_http): + store = Store(name="Test Shop") + items = [ + InvoiceItem( + name="Product A", quantity=2, - unit_price="35000", - total_price="70000", - description="VIP Tickets for the Youssou N'dour Event" + unit_price="5000", + total_price="10000", + description="Desc A", ) ] - self.invoice = paydunya.Invoice(self.store) - self.invoice.add_items(self.items * 10) - # taxes are (key,value) pairs - self.invoice.add_taxes([("Other TAX", 700), ("VAT", 5000)]) - self.invoice.add_custom_data([("phone_brand", "Motorola V3"), - ("model", "65456AH23")]) - - def tearDown(self): - unittest.TestCase.tearDown(self) - self.invoice = None - - def test_create_invoice(self): - status, _ = self.invoice.create() - self.assertTrue(status) - - def test_add_items(self): - _items = len(self.invoice.items) - self.invoice.add_items(self.items * 2) - self.assertTrue(len(self.invoice.items) > _items) - - def test_add_taxes(self): - _taxes = len(self.invoice.taxes) - self.invoice.add_taxes([("Foo_TAX", 9)]) - self.assertTrue(len(self.invoice.taxes) > _taxes) - - def test_add_custom_data(self): - _data = len(self.invoice.custom_data) - self.invoice.add_custom_data([("Category", "Sports")]) - self.assertTrue(len(self.invoice.custom_data) > _data) + invoice = Invoice(client_test, store) + invoice.add_items(items) + invoice.set_total_amount(10000) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00", "response_text": "OK"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert "item_0" in payload["invoice"]["items"] + assert payload["invoice"]["items"]["item_0"]["name"] == "Product A" + assert payload["invoice"]["items"]["item_0"]["quantity"] == "2" + + def test_multiple_items_sequential_keys(self, client_test, mock_http): + store = Store(name="Test Shop") + items = [ + InvoiceItem(name="A", quantity=1, unit_price="10", total_price="10"), + InvoiceItem(name="B", quantity=1, unit_price="20", total_price="20"), + InvoiceItem(name="C", quantity=1, unit_price="30", total_price="30"), + ] + invoice = Invoice(client_test, store) + invoice.add_items(items) + invoice.set_total_amount(60) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert list(payload["invoice"]["items"].keys()) == ["item_0", "item_1", "item_2"] + + def test_taxes_keyed_as_tax_0(self, client_test, mock_http): + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + invoice.add_tax("TVA", 6300) + invoice.set_total_amount(6300) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert "tax_0" in payload["invoice"]["taxes"] + assert payload["invoice"]["taxes"]["tax_0"]["name"] == "TVA" + + def test_empty_items_not_included_in_payload(self, client_test, mock_http): + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + invoice.set_total_amount(500) + invoice.set_description("Test invoice") + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert "items" not in payload["invoice"] + + def test_customer_node_in_payload(self, client_test, mock_http): + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + invoice.set_total_amount(5000) + invoice.set_customer(name="John Doe", email="john@example.com", phone="771111111") + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert "customer" in payload["invoice"] + assert payload["invoice"]["customer"]["name"] == "John Doe" + assert payload["invoice"]["customer"]["email"] == "john@example.com" + assert payload["invoice"]["customer"]["phone"] == "771111111" + + def test_customer_not_included_when_empty(self, client_test, mock_http): + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + invoice.set_total_amount(5000) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert "customer" not in payload["invoice"] + + def test_channels_in_payload(self, client_test, mock_http): + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + invoice.set_total_amount(5000) + invoice.add_channels(["card", "wave-senegal"]) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert payload["invoice"]["channels"] == ["card", "wave-senegal"] + + def test_actions_in_payload(self, client_test, mock_http): + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + invoice.set_total_amount(5000) + invoice.set_cancel_url("https://example.com/cancel") + invoice.set_return_url("https://example.com/return") + invoice.set_callback_url("https://example.com/cb") + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert payload["actions"]["cancel_url"] == "https://example.com/cancel" + assert payload["actions"]["return_url"] == "https://example.com/return" + assert payload["actions"]["callback_url"] == "https://example.com/cb" + + def test_actions_not_included_when_empty(self, client_test, mock_http): + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + invoice.set_total_amount(5000) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert "actions" not in payload + + def test_custom_data_in_payload(self, client_test, mock_http): + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + invoice.set_total_amount(5000) + invoice.add_custom_data({"cart_id": 123, "coupon": "SUMMER"}) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert payload["custom_data"]["cart_id"] == 123 + assert payload["custom_data"]["coupon"] == "SUMMER" + + def test_confirm_is_get_request(self, client_test, mock_http): + mock_http.add_response( + method="GET", + url=f"{TEST_BASE}/checkout-invoice/confirm/test_token_123", + json={ + "response_code": "00", + "response_text": "Transaction Found", + "status": "completed", + }, + ) + + store = Store(name="Test Shop") + invoice = Invoice(client_test, store) + resp = invoice.confirm("test_token_123") + + assert resp["status"] == "completed" + assert mock_http.get_requests()[0].method == "GET" + + def test_calculate_total(self, client_test): + store = Store(name="Test Shop") + items = [ + InvoiceItem(name="A", quantity=1, unit_price="100", total_price="100"), + InvoiceItem(name="B", quantity=2, unit_price="200", total_price="400"), + ] + invoice = Invoice(client_test, store) + invoice.add_items(items) + + assert invoice.calculate_total() == 500.0 + + def test_total_amount_falls_back_to_calculated(self, client_test, mock_http): + store = Store(name="Test Shop") + items = [ + InvoiceItem(name="A", quantity=1, unit_price="100", total_price="150"), + ] + invoice = Invoice(client_test, store) + invoice.add_items(items) + + mock_http.add_response( + method="POST", + url=f"{TEST_BASE}/checkout-invoice/create", + json={"response_code": "00"}, + ) + + invoice.create() + + req = mock_http.get_requests()[0] + payload = json.loads(req.content) + + assert payload["invoice"]["total_amount"] == 150.0 diff --git a/tests/test_ipn.py b/tests/test_ipn.py new file mode 100644 index 0000000..9c89542 --- /dev/null +++ b/tests/test_ipn.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +import hashlib + +from paydunya.ipn import verify_ipn_hash + + +def test_verify_valid_hash(): + master_key = "my-super-secret-master-key" + expected = hashlib.sha512(master_key.encode()).hexdigest() + assert verify_ipn_hash(master_key, expected) is True + + +def test_verify_invalid_hash(): + master_key = "my-super-secret-master-key" + assert verify_ipn_hash(master_key, "definitely-not-the-right-hash") is False + + +def test_different_keys_produce_different_hashes(): + key_a = "key-alpha" + key_b = "key-beta" + hash_a = hashlib.sha512(key_a.encode()).hexdigest() + hash_b = hashlib.sha512(key_b.encode()).hexdigest() + + assert hash_a != hash_b + assert verify_ipn_hash(key_a, hash_a) is True + assert verify_ipn_hash(key_a, hash_b) is False + + +def test_empty_key(): + empty_hash = hashlib.sha512(b"").hexdigest() + assert verify_ipn_hash("", empty_hash) is True + assert verify_ipn_hash("", "not-empty-hash") is False diff --git a/tests/test_opr.py b/tests/test_opr.py deleted file mode 100644 index c147447..0000000 --- a/tests/test_opr.py +++ /dev/null @@ -1,37 +0,0 @@ -import unittest -import paydunya -from . import PAYDUNYA_ACCESS_TOKENS - -paydunya.debug = True -paydunya.api_keys = PAYDUNYA_ACCESS_TOKENS - - -class TestOPR(unittest.TestCase): - def setUp(self): - self.opr_data = {'account_alias': '774563209', - 'description': 'Hello World', - 'total_amount': 345} - store = paydunya.Store(name="Event Shop") - self.opr = paydunya.OPR(self.opr_data, store) - - def tearDown(self): - self.opr = None - - def test_opr_create(self): - status, resp = self.opr.create() - self.assertTrue(status) - - status, _ = self.opr.create(self.opr_data) - self.assertTrue(status) - - def test_opr_charge(self): - status, response = self.opr.create() - token = response['token'] - status, _ = self.opr.charge({'token': token, - 'confirm_token': "56Y8"}) - # request should because the token and - # confirm_token combination are wrong - self.assertFalse(status) - -if __name__ == '__main__': - unittest.main() diff --git a/tox.ini b/tox.ini index 1a80501..d9ba0f5 100644 --- a/tox.ini +++ b/tox.ini @@ -1,17 +1,19 @@ [tox] -envlist = py26, py27, py33, style +envlist = py310, py311, py312, py313, lint +requires = tox-uv>=1.11 [testenv] -setenv = - PYTHONPATH = {toxinidir}:{toxinidir}/paydunya +runner = uv-venv-lock-runner +package = wheel deps = - -r{toxinidir}/requirements.txt - pytest + pytest>=8.2 + pytest-cov>=5.0 commands = - py.test --basetemp={envtmpdir} + pytest --cov=paydunya --cov-report=term {posargs} -[testenv:style] +[testenv:lint] deps = - -r{toxinidir}/requirements.txt + ruff>=0.5 commands = - python setup.py flake8 + ruff check src/paydunya tests + ruff format --check src/paydunya tests diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..ce26710 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1176 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] + +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + +[[package]] +name = "backrefs" +version = "7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/a7dd63622beef68cc0d3c3c36d472e143dd95443d5ebf14cd1a5b4dfbf11/backrefs-7.0.tar.gz", hash = "sha256:4989bb9e1e99eb23647c7160ed51fb21d0b41b5d200f2d3017da41e023097e82", size = 7012453, upload-time = "2026-04-28T16:28:04.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/39/39a31d7eae729ea14ed10c3ccef79371197177b9355a86cb3525709e8502/backrefs-7.0-py310-none-any.whl", hash = "sha256:b57cd227ea556b0aed3dc9b8da4628db4eabc0402c6d7fcfc69283a93955f7e9", size = 380824, upload-time = "2026-04-28T16:27:55.647Z" }, + { url = "https://files.pythonhosted.org/packages/c9/b5/9302644225ba7dfa934a2ff2b9c7bb85701313a90dddb3dfaf693fa5bae2/backrefs-7.0-py311-none-any.whl", hash = "sha256:a0fa7360c63509e9e077e174ef4e6d3c21c8db94189b9d957289ae6d794b9475", size = 392626, upload-time = "2026-04-28T16:27:57.42Z" }, + { url = "https://files.pythonhosted.org/packages/36/da/87912ddec6e06feffbaa3d7aa18fc6352bee2e8f1fee185d7d1690f8f4e8/backrefs-7.0-py312-none-any.whl", hash = "sha256:ca42ce6a49ace3d75684dfa9937f3373902a63284ecb385ce36d15e5dcb41c12", size = 398537, upload-time = "2026-04-28T16:27:58.913Z" }, + { url = "https://files.pythonhosted.org/packages/00/bb/90ba423612b6aa0adccc6b1874bcd4a9b44b660c0c16f346611e00f64ac3/backrefs-7.0-py313-none-any.whl", hash = "sha256:f2c52955d631b9e1ac4cd56209f0a3a946d592b98e7790e77699339ae01c102a", size = 400491, upload-time = "2026-04-28T16:28:00.928Z" }, + { url = "https://files.pythonhosted.org/packages/3e/5c/fb93d3092640a24dfb7bd7727a24016d7c01774ca013e60efd3f683c8002/backrefs-7.0-py314-none-any.whl", hash = "sha256:a6448b28180e3ca01134c9cf09dcebafad8531072e09903c5451748a05f24bc9", size = 412349, upload-time = "2026-04-28T16:28:02.412Z" }, +] + +[[package]] +name = "cachetools" +version = "7.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/8b/0d3945a13955303b81272f759a0331e54c5c793da455e6f5706b89d2639c/cachetools-7.1.4.tar.gz", hash = "sha256:437f55a4e0c1b01a4f3077cc470e6991d47430970e36fbcb77e2be0df4fc1cd6", size = 40085, upload-time = "2026-05-21T22:40:43.376Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/7b/1fc1c09cc0756cf25861a3be10565915953876da48bb228fb9a672b20a42/cachetools-7.1.4-py3-none-any.whl", hash = "sha256:323dc4127934744db5b54eb4924482d7edafbf9554e820d1531c2e08c0e4ef54", size = 16761, upload-time = "2026-05-21T22:40:41.845Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd6280cf040f233bd7d3407b743b4b4c74f70e8e1c4199cb112a62c941c0772a", size = 322240, upload-time = "2026-07-07T14:32:36.236Z" }, + { url = "https://files.pythonhosted.org/packages/de/d1/b4319dc3229d8272fba305e206fc0a148e2de8d4087917ce62ae6382f359/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa99adc8f081b475a12843953db36831eaf83ec33eb46a90629ca6a5de45a616", size = 216475, upload-time = "2026-07-07T14:32:38.142Z" }, + { url = "https://files.pythonhosted.org/packages/80/33/6c99c1b3e6b8bf730e1bc809b9a2608f224145069114c479a2e9e1494346/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c1225416b463483160e4af85d5fc3a9690ccb53fd4b1865a6437825f5ede3209", size = 238670, upload-time = "2026-07-07T14:32:39.658Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f4/ffbb83546e1f198ecc70ecd372b65cf2b50f9068b380abd67640f17a8e18/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d10d789dd9bcca1173c95af82c58433122564b7bc39385124be735a35cbe99", size = 233476, upload-time = "2026-07-07T14:32:41.155Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5f/b98b8da398637b551e427e7be922bdec19177dc54d6811dcdaa503f23aac/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bb41182d93ea91f60b4bc8fbf4c820c69ef8a12ab2d917f3f1834f1acad07e8", size = 223817, upload-time = "2026-07-07T14:32:42.592Z" }, + { url = "https://files.pythonhosted.org/packages/36/31/a276bb2e66243072a3fd06fdcab9cbb61a305b02143d70d2bda21d888fa8/charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:bcf74c1df76758a395bf0af608c04c82257523f55c9868b334f06270d0f2112b", size = 207974, upload-time = "2026-07-07T14:32:44.258Z" }, + { url = "https://files.pythonhosted.org/packages/5e/be/7ee4453d7e88dfbc4104ccd34900b9f2c7c17dac22881865fe0e82424a25/charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b5314963fce9b0b12743891de876e724997864ee22aa496f903f426c7e2fa5b2", size = 221655, upload-time = "2026-07-07T14:32:45.64Z" }, + { url = "https://files.pythonhosted.org/packages/1d/85/181c652953eb5276d198f375b1dd641047392050098100a3a02d6534f657/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e9701d0049d92c16703a42771b98d560b95248949f23f8cf7b4eddd201814fb9", size = 219229, upload-time = "2026-07-07T14:32:47.376Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e7/aaf6da33fc9f4691cda8f7efbc9f69179d3d39ec8a4799baf273ee1d8db0/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:65a7ff3f705e57d392f7261b6d0550fe137c3019477431f1c355e0db0a7d3e15", size = 209704, upload-time = "2026-07-07T14:32:48.855Z" }, + { url = "https://files.pythonhosted.org/packages/63/01/f2fb3bd3a73be48b173ee0c6aa8d2497af97d5663a8c4c4b491de4c62f7a/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79580094b00d1789d1f93ea55bc43cb2f611910c72235b7657f3482ddcc1b22d", size = 226243, upload-time = "2026-07-07T14:32:50.239Z" }, + { url = "https://files.pythonhosted.org/packages/c4/02/c57a22739fe05246b0b5783b3bfb6afaac4eebb46f3ececdfb2f048f780e/charset_normalizer-3.4.9-cp310-cp310-win32.whl", hash = "sha256:432786d3561e69aeeae6c7e8648964ce0ad05736120135601f87ac26b9c83381", size = 150935, upload-time = "2026-07-07T14:32:51.676Z" }, + { url = "https://files.pythonhosted.org/packages/37/8d/ca39a7559a4797505530d084fd3a49a2c959efbbbff146302fb7be4e3b35/charset_normalizer-3.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:8c041122946b7ba21bb32c45b1aa57b1be35527690aeb3c5c234521085632eee", size = 162314, upload-time = "2026-07-07T14:32:53.193Z" }, + { url = "https://files.pythonhosted.org/packages/01/da/a44bd7a13d426e69e4894557106cd58669097bfad4a8681123b618fbfc5d/charset_normalizer-3.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:375b83ed0aecfce76c16d198fbc21f3b11b337d68662bea0a995046682a11419", size = 153075, upload-time = "2026-07-07T14:32:54.554Z" }, + { url = "https://files.pythonhosted.org/packages/0b/e3/85ec501f206fb049259288c1f3506e53876937fb00edb47009348e66756b/charset_normalizer-3.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e94703ec9684807f20cfb5eed95c70f67f2a8f21ad620146d7b5a13677b93e5", size = 317075, upload-time = "2026-07-07T14:32:56.021Z" }, + { url = "https://files.pythonhosted.org/packages/c3/69/2a5385192e67175f7d8bd5ce4f57c24bc956439adeae5c13a99aa28a53d1/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a441ea71902098ffe78c5abe6c494f44160b4af614ed16c3d9a3b1d17fd8ee2", size = 213837, upload-time = "2026-07-07T14:32:57.78Z" }, + { url = "https://files.pythonhosted.org/packages/b3/46/03ddc7da576d814fe0a36dd1f0fd3258e95404b4b2e3c026b7923d7e133f/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:304b13570067b2547562e308af560b3963857b1fa90bd6afd978130130fe2d6a", size = 235503, upload-time = "2026-07-07T14:32:59.205Z" }, + { url = "https://files.pythonhosted.org/packages/4e/6e/de0229a7ef40f6f9d28a837eebf4ec47bdca5dab4e900c84f22919af636a/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4773092f8019072343a7447203308b176e10199920eb02d6195e81bbb3274c29", size = 229944, upload-time = "2026-07-07T14:33:00.803Z" }, + { url = "https://files.pythonhosted.org/packages/a5/34/49b9060e8418b14fb5cba9cf6bfb383111e2538a03a1fb18e66a95aeb3d5/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04ce310cb89c15df659582aee80a0603788732a5e017d5bd5c81158106ce249c", size = 221276, upload-time = "2026-07-07T14:33:02.199Z" }, + { url = "https://files.pythonhosted.org/packages/44/95/80282cce0fae9c3061203d723ee87da996aed79679e65d8935050ee7ca1f/charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:c0323c9daef75ef2e5083624b4585018a0c9d5e3b40f607eed81a311270b934b", size = 205260, upload-time = "2026-07-07T14:33:03.698Z" }, + { url = "https://files.pythonhosted.org/packages/0c/74/2f62c8821b969ea3bd67cc2e6976834f48ca5d12664d2559ebcd9bcfbed7/charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:871ff67ea1aad4dfd91736464934d56b32dac49f9fbe16cddba36198a7b3a0db", size = 217786, upload-time = "2026-07-07T14:33:05.12Z" }, + { url = "https://files.pythonhosted.org/packages/d9/8d/feabb82cb49fcad14515b1d7d1ca4787b0da7fc723a212bf89bc9e0fac52/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:67830fc78e67501f47bb950471b2dcb9b35b140084429318e862895a8e89c993", size = 216798, upload-time = "2026-07-07T14:33:06.629Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ff/c946d63bc3786d5b84d960b0f7ab7e25b828486a946b5aa997625bcaf6a6/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3d92613ec25e43b05f042302531ec0f00b8445190e43325880cbd6ab7c2581da", size = 206429, upload-time = "2026-07-07T14:33:08.006Z" }, + { url = "https://files.pythonhosted.org/packages/af/ba/5e5007c370702f85d2ef75791fac7943ed41e080364a673b20142e430e3e/charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:280081916dc341820640489a66e4696049401ef1cf6dd672f672e70ad915aca3", size = 223066, upload-time = "2026-07-07T14:33:09.783Z" }, + { url = "https://files.pythonhosted.org/packages/83/d5/9096aa3cf532dfad237861544eb47a0f20d5adbf1039760fed8eaae935d9/charset_normalizer-3.4.9-cp311-cp311-win32.whl", hash = "sha256:ac351b3b8014eead140e77e9717e2992c6bbe30b63bc3422422eb84865412e3d", size = 150456, upload-time = "2026-07-07T14:33:11.217Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a1/e29995109e455dc8eff8d0fac6ae509be39561318a7cfeac5d33ad029213/charset_normalizer-3.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:6366a16e1a25018694d6a5d784d09b046edc9eac40ea2b54065c3052672516a1", size = 161410, upload-time = "2026-07-07T14:33:12.743Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8d/1569f4d0032d6ba2a4fe4591c35bf87868c600c41a71eb5c2e1ffa8464c2/charset_normalizer-3.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:1d22856ffbe153a602df38e4a5464f0b748a54002e0d69ac6d2ad0a197cc99ec", size = 152649, upload-time = "2026-07-07T14:33:14.173Z" }, + { url = "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0", size = 319300, upload-time = "2026-07-07T14:33:15.666Z" }, + { url = "https://files.pythonhosted.org/packages/ec/96/5d9364e3342d69f3a045e1777bc47c85c383e6e9466d561b33fdb419d1f9/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9", size = 215802, upload-time = "2026-07-07T14:33:17.031Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4c/5361f9aa7f2cb58d94f2ab831b3d493f69efb1d239654b4744e3c09527cb/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44", size = 237171, upload-time = "2026-07-07T14:33:18.576Z" }, + { url = "https://files.pythonhosted.org/packages/50/78/ce342ca4ff30b2eb49fe6d9578df85974f90c67d294113e94efdd9664cbd/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9", size = 233075, upload-time = "2026-07-07T14:33:20.084Z" }, + { url = "https://files.pythonhosted.org/packages/01/c4/4fa4c8b3097a11f3c5f09a35b72ed6855fb1d332469504962ab7bafcc702/charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd", size = 224256, upload-time = "2026-07-07T14:33:21.747Z" }, + { url = "https://files.pythonhosted.org/packages/87/3a/ad914516df7e358a81aae018caa5e0470ba827fa6d763b1d2e87d920a5f6/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84", size = 208784, upload-time = "2026-07-07T14:33:23.313Z" }, + { url = "https://files.pythonhosted.org/packages/d7/74/3c12f9755717dfe5c5c87da63f35d765fa0c00382ec26bf23f7fae34f2ba/charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b", size = 219928, upload-time = "2026-07-07T14:33:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/33/9a/895095b83e7907abd6d3d99aad3a38ad0d9686cc186cb0c94c24320fe63e/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde", size = 218489, upload-time = "2026-07-07T14:33:26.42Z" }, + { url = "https://files.pythonhosted.org/packages/a1/34/ef5c05f412f42520d7709b7d3784d19640839eb7366ded1755511585429f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39", size = 210267, upload-time = "2026-07-07T14:33:27.952Z" }, + { url = "https://files.pythonhosted.org/packages/83/dc/9b29fa4412b318bf3bfea985c35d67eb55e04b59a7c3f2237168b0e0be6f/charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62", size = 226030, upload-time = "2026-07-07T14:33:29.397Z" }, + { url = "https://files.pythonhosted.org/packages/0e/42/6dbc00b8cd16011691203e33570fa42ed5746599a2e878112d16eab403a3/charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642", size = 151185, upload-time = "2026-07-07T14:33:30.781Z" }, + { url = "https://files.pythonhosted.org/packages/80/cc/f920afd1a23c58ccd53c1d36085a71893a4737ff5e66e0371efab6809850/charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0", size = 162557, upload-time = "2026-07-07T14:33:32.176Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/0386d43a261ff4e4b30c5857af7df877254b46bec7b9d1b74b6bf969a90b/charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2", size = 152665, upload-time = "2026-07-07T14:33:33.711Z" }, + { url = "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:440eede837960000d74978f0eba527be106b5b9aee0daf779d395276ed0b0614", size = 317688, upload-time = "2026-07-07T14:33:35.408Z" }, + { url = "https://files.pythonhosted.org/packages/d0/39/8ff066c672434225f8d25f8b739f992af250944392173dcc88362681c9bf/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21e764fd1e70b6a3e205a0e46f3051701f98a8cb3fad66eeb80e48bb502f8698", size = 214982, upload-time = "2026-07-07T14:33:36.996Z" }, + { url = "https://files.pythonhosted.org/packages/92/8f/3a47a3667c83c2df9483d91644c6c107de3bf8874aa1793da9d3012eb986/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e4fd89cc178bced6ad29cb3e6dd4aa63fa5017c3524dbd0b25998fb64a87cc8b", size = 236460, upload-time = "2026-07-07T14:33:38.536Z" }, + { url = "https://files.pythonhosted.org/packages/f1/60/b22cdbee7e4013dab8b0d7647fc6181120fbbbc8f7025c226d15bd5a47fc/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bd47ba7fc3ca94896759ea0109775132d3e7ab921fbf54038e1bab2e46c313c9", size = 232003, upload-time = "2026-07-07T14:33:40.059Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f8/72eb13dcabe7257035cea8aefd922caad2f110d252bf9f67c4c2ca763aee/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:84fd18bcc17526fc2b3c1af7d2b9217d32c9c04448c16ec693b9b4f1985c3d33", size = 223149, upload-time = "2026-07-07T14:33:41.631Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3e/faee8f9de92b14ee1198e9163252bb15efee7301b31256a3b6d9ebfdd0dd/charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:5b10cd92fc5c498b35a8635df6d5a100207f88b63a4dc1de7ef9a548e1e2cd63", size = 207901, upload-time = "2026-07-07T14:33:43.209Z" }, + { url = "https://files.pythonhosted.org/packages/3a/25/45f30093ae27dd7b92a793b61882a38685f993700113ca36e0c9c14965e1/charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4fbdde9dd4a9ce5fd52c2b3a347bb50cc89483ef783f1cb00d408c13f7a96c0", size = 219176, upload-time = "2026-07-07T14:33:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/48/18/c8f397329c35e32f6a837e488986f4ae03bd2abebc453b48714991630c2f/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:416c229f77e5ea25b3dfd4b582f8d73d7e43c22320302b9ab128a2d3a0b38efe", size = 217356, upload-time = "2026-07-07T14:33:46.192Z" }, + { url = "https://files.pythonhosted.org/packages/86/7e/5ce0bba863470fd1902d5e5843968951bddf38abe4742fc97116ef4598b3/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:75286256590a6320cf106a0d28970d3560aad9ee09aa7b34fb40524792436d35", size = 209614, upload-time = "2026-07-07T14:33:47.705Z" }, + { url = "https://files.pythonhosted.org/packages/6c/ef/2473d3c4d869155be4af1191111d59c4d5c4e0173026f7e85b176e23bf65/charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69b157c5d3292bcd443faca052f3096f637f1e074b98212a933c074ae23dc3b8", size = 224991, upload-time = "2026-07-07T14:33:49.238Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a3/53ddae3db108a088156aa8ddfafd411ebbc1340f48c5573f697b27f69a39/charset_normalizer-3.4.9-cp313-cp313-win32.whl", hash = "sha256:51307f5c71007673a2bf8232ad973483d281e74cb99c8c5a990af1eefa6277d9", size = 150622, upload-time = "2026-07-07T14:33:50.711Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ef/6953a77c7cf2c2ff9998e6f575ab3e380119f100223381565a4f94c1f836/charset_normalizer-3.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:fe2c7201c642b7c308f1675355ad7ff7b66acfe3541625efe5a3ad38f29d6115", size = 161947, upload-time = "2026-07-07T14:33:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/6e/fb/d560d1d1555debbfe7849d9cac6145c1b537709d79576bf22557ed803b82/charset_normalizer-3.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:611057cc5d5c0afc743ba8be6bd828c17e0aaa8643f9d0a9b9bb7dea80eb8012", size = 152594, upload-time = "2026-07-07T14:33:53.486Z" }, + { url = "https://files.pythonhosted.org/packages/7e/8d/496817fa0944239ecae662dd57ea765cfeaec6a735f9f025d4b7b72e7143/charset_normalizer-3.4.9-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:0327fcd59a935777d83410750c50600ee9571af2846f71ce40f25b13da1ef380", size = 317253, upload-time = "2026-07-07T14:33:54.994Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f9/ef4a69ea338ad3c0deceea0f5f7d2380ae8b52132b06d652cb0d2cd86706/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a79d9f4d8001473a30c163556b3c3bfebec837495a412dde78b51672f6134f9", size = 215898, upload-time = "2026-07-07T14:33:56.334Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e7/5ddfd76fc061eb52de219658a4aa431cbacadf0a0219c8854f00da50d289/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33bdcc2a32c0a0e861f60841a512c8acc658c87c2ac59d89e3a46dacf7d866e4", size = 236718, upload-time = "2026-07-07T14:33:57.9Z" }, + { url = "https://files.pythonhosted.org/packages/49/ba/768fa3f36048d81c477a0ce61f813bc1454d80917ccfe550abd9f44f5e24/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f840ed6d8ecba8255df8c42b87fadeda98ddfc6eeec05e2dc66e26d46dd6f58a", size = 232519, upload-time = "2026-07-07T14:33:59.811Z" }, + { url = "https://files.pythonhosted.org/packages/f4/c4/b3e049d2aa3766180c78507110543d9d50894cc97f57de543f1be521dcdc/charset_normalizer-3.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c25fe15c70c59eb7c5ce8c06a1f3fa1da0ecc5ea1e7a5922c40fd2fa9b0d5046", size = 223143, upload-time = "2026-07-07T14:34:01.517Z" }, + { url = "https://files.pythonhosted.org/packages/19/79/55c32d06d76ae4feafe053f061f3e3ab70bcf19f4007797ce8c3efda7830/charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:f7fb7d750cfa0a070d2c24e831fd3481019a60dd317ea2b39acbcebc08b6ed81", size = 206742, upload-time = "2026-07-07T14:34:03.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/e0/47c079dd82d217c807479cd59ffd30af56307ea31c108b75758970459ad3/charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1c96a7a18b9690a4d46df09e3e3382406ae3213727cd1019ebade1c4a81917", size = 219191, upload-time = "2026-07-07T14:34:04.657Z" }, + { url = "https://files.pythonhosted.org/packages/42/ab/b9bc2e77d6b44a7e46ef62ec5cac1c9a6ba7b9135a5d560f002696ec9995/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a4cfde78a9f2880208d16a93b795726a3017d5977e08d1e162a7a31322479c41", size = 218328, upload-time = "2026-07-07T14:34:06.115Z" }, + { url = "https://files.pythonhosted.org/packages/f1/78/c9c71d599f5aa2d42bcdd35cbbd46d7f535351a57e40ff7d8e5a7e219401/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4d6fcde76f94f5cb9e43e9e9a61f16dacefd228cbbf6f1a09bd9b219a92f1a1", size = 207406, upload-time = "2026-07-07T14:34:07.554Z" }, + { url = "https://files.pythonhosted.org/packages/f6/39/c914445c321a845097ce4f6ac7de9a18228a77b766272125a1ce00d851eb/charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:898f0e9068ca27d37f8e83a5b962821df851532e6c4a7d615c1c033f9da6eedf", size = 225157, upload-time = "2026-07-07T14:34:09.061Z" }, + { url = "https://files.pythonhosted.org/packages/9b/f2/c0d4b8508565a36bc5c624e88ed297f5b0b1095011034d7f5b83a69908b5/charset_normalizer-3.4.9-cp314-cp314-win32.whl", hash = "sha256:c1c948747b03be832dceed96ca815cef7360de9aa19d37c730f8e3f6101aca48", size = 151095, upload-time = "2026-07-07T14:34:10.901Z" }, + { url = "https://files.pythonhosted.org/packages/49/fd/a1d26144398c67486422a72bf5812cda22cb4ccfcd95a290fb41ceb4b8e2/charset_normalizer-3.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:16b65ea0f2465b6fb52aa22de5eca612aa964ddfec00a912e26f4656cbef890b", size = 162796, upload-time = "2026-07-07T14:34:12.47Z" }, + { url = "https://files.pythonhosted.org/packages/20/95/d75e82f8ce9fd323ebf059c16c9aadefb22a1ecde13b7840b35835e4886c/charset_normalizer-3.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:40a126142a56b2dfc0aacbad1de8310cbf60da7656db0e6b16eebd48e3e93519", size = 153334, upload-time = "2026-07-07T14:34:14.044Z" }, + { url = "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:609b3ba8fcc0fb5ab7af00719d0fb6ad0cb518e48e7712d12fd68f1327951198", size = 338848, upload-time = "2026-07-07T14:34:15.688Z" }, + { url = "https://files.pythonhosted.org/packages/cd/91/7253a32e86b7e1d1239b1b36ba6dd0f021a21107ab33054b53119cc083b9/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51447e9aa2684679af07ca5021c3db526e0284347ebf4ffcec1154c3350cfe32", size = 223022, upload-time = "2026-07-07T14:34:17.248Z" }, + { url = "https://files.pythonhosted.org/packages/cb/32/2e64bd2be10e89c61e57ebe6a93fd98ae88eb7ebe414b5121f22c96c69eb/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cc1b0fff8ead343dae06305f954eb8468ba0ec1a97881f42489d198e4ce3c632", size = 241590, upload-time = "2026-07-07T14:34:18.813Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ef/d96ec496cfea0c21db43b0ad03891308b02388d054cc902cf0e5a1ad6a88/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa36ec09ef71d158186bc79e359ff5fdd6e7996fe8ab638f00d6b93139ba4fcf", size = 239584, upload-time = "2026-07-07T14:34:20.52Z" }, + { url = "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df115d4d83168fdf2cae48ef1ff6d1cb4c466364e30861b37121de0f3bf1b990", size = 230224, upload-time = "2026-07-07T14:34:22.189Z" }, + { url = "https://files.pythonhosted.org/packages/52/94/af74dde74a3996bd959c350709bfe50e297823d70a8c1cbd54b838880863/charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f86c6358749bd4fda175388691e3ba8c46e24c5347d0afd20f9b7edfc9faf07d", size = 212667, upload-time = "2026-07-07T14:34:23.857Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f0/f1c4fe746c395922961b5916ed1d7d6e7d4c84851d19ed43cc89980ec953/charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:32286a2c8d167e897177b673176c1e3e00d4057caf5d2b64eef9a3666b03018e", size = 227179, upload-time = "2026-07-07T14:34:25.586Z" }, + { url = "https://files.pythonhosted.org/packages/e4/56/6c745619ac397e8871e2bcd3cea1eec86b877488f33888b3aef5c3ed506e/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:83aed2c10721ddd90f68140685391b50811a880af20654c59af6b6c66c40513c", size = 225372, upload-time = "2026-07-07T14:34:27.212Z" }, + { url = "https://files.pythonhosted.org/packages/78/ad/98aae8630ac71f16711968e38a5acfecce41b778bf2f0312851020f565a8/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cd6c3d4b783c556fa00bf540854e42f135e2f256abd29669fcd0da0f2dec79c2", size = 215222, upload-time = "2026-07-07T14:34:28.774Z" }, + { url = "https://files.pythonhosted.org/packages/f7/40/9593d54209765207a7f11073c06494c1721e4ca4a0a426c597679bf7f91e/charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ee2f2a527e3c1a6e6411eb4209642e138b544a2d72fe5d0d76daf77b24063534", size = 231958, upload-time = "2026-07-07T14:34:30.345Z" }, + { url = "https://files.pythonhosted.org/packages/b1/27/693ee5e8a18191eb38647360c51cd505013e2bd3b366aa43fd5344c21e3c/charset_normalizer-3.4.9-cp314-cp314t-win32.whl", hash = "sha256:0d861473f743244d349b50f850d10eb87aeb22bbdcc8e64f79273c94af5a8226", size = 155580, upload-time = "2026-07-07T14:34:31.884Z" }, + { url = "https://files.pythonhosted.org/packages/80/3f/bd97d3d9c613013d07cb7733d299385b41df37f0471310f5a73dc359f0b8/charset_normalizer-3.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:9b8e0f3107e2200b76f6054de99016eac3ee6762713587b36baaa7e4bd2ae177", size = 167620, upload-time = "2026-07-07T14:34:33.438Z" }, + { url = "https://files.pythonhosted.org/packages/3d/c6/eee9dca4439b1061f76373f06ea855678cc4a64c1c3c90b50e479edbb8eb/charset_normalizer-3.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:19ac87f93086ce37b86e098888555c4b4bc48102279bae3350098c0ed664b501", size = 158037, upload-time = "2026-07-07T14:34:35.018Z" }, + { url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" }, +] + +[[package]] +name = "click" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.15.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/d0/55fe630f4cf94e3fcba868240fad8c8cdd1f764e2a932f8926347e6ec4cd/coverage-7.15.2.tar.gz", hash = "sha256:3df60dc267f0a2ca23cb7a9ab1109c62b9335ffbf519fcfe167157c28c09b81d", size = 927741, upload-time = "2026-07-15T18:56:19.558Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/03/060ce69008ac97bbc01b1411b3e55b61f6f015659400b46749b662107831/coverage-7.15.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b5bd92ff1ec22e535eab0de75fa6db021992791f461a2aceb7822c625a1187d", size = 221284, upload-time = "2026-07-15T18:53:29.52Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a3/d936e8b53edd9684100a6aefaf3fcabaa54728fe33324436c8d279c047aa/coverage-7.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:44826758cfe73fcd0e6af5deb4ba6d5417cc1d13df3acb35c93484a11160f846", size = 221799, upload-time = "2026-07-15T18:53:31.708Z" }, + { url = "https://files.pythonhosted.org/packages/ae/a3/ca234b06aec7ee28226f11d39a696b4481fe5eddfce8e03bf39979bb8ffb/coverage-7.15.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09f5c6ec5901f667bd97dd140b5b9a2586b10efec66f46fb1e6d8135f8b95bdf", size = 248544, upload-time = "2026-07-15T18:53:33.212Z" }, + { url = "https://files.pythonhosted.org/packages/2b/89/dda79527bb7573ba91828b2fb91b3105d87378d6a2749ca0c0924ce0addd/coverage-7.15.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1d16e3a7104ea84f03e614611b3edbf6fb6892554b3ab0fe7fbb3f2b2ef04376", size = 250374, upload-time = "2026-07-15T18:53:34.683Z" }, + { url = "https://files.pythonhosted.org/packages/67/c6/c33755a34572f81f49a8c0cdf6b622f35ccb3238b136e1909daf0cdd4319/coverage-7.15.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d46e62cb35d91e6e2589fda6d28074426b0e276422b5d2ebef2c6b11dc60dbfd", size = 252239, upload-time = "2026-07-15T18:53:36.205Z" }, + { url = "https://files.pythonhosted.org/packages/b9/6f/dc341741b375be53a5baeee5b4bf0f0e525d38caed428f7932d23bb7bcb1/coverage-7.15.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dfd3db045e95960ae3683059571e597fda7cc610106a8916f77c5839048c1deb", size = 254150, upload-time = "2026-07-15T18:53:37.863Z" }, + { url = "https://files.pythonhosted.org/packages/e9/8d/966a18a5b195cb4e77b14c53f5f3dce22b5da05e6de7fafd1e08f2d2067a/coverage-7.15.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:affd532502d34c0472d0cdb181325c89f1d2c44992fef0c17e88e7b1576259a1", size = 249234, upload-time = "2026-07-15T18:53:39.394Z" }, + { url = "https://files.pythonhosted.org/packages/c5/8b/8b2e367496ab48484d48e79984fec76cdc1b7cb5d3a00ee799a5602e3ec9/coverage-7.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d17d7512151fedfcc64c1821a8977fc9be0dbf495754669afcab7b57abc98ae9", size = 250276, upload-time = "2026-07-15T18:53:41.027Z" }, + { url = "https://files.pythonhosted.org/packages/63/92/1199318a200eb6c8c6ce0192c892c8710ac791abbe0f35099294620bbfda/coverage-7.15.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e26ff680768b8095e8874aabe0e9d3a47a2a9f176a8340d05f8604c56457c23a", size = 248283, upload-time = "2026-07-15T18:53:42.557Z" }, + { url = "https://files.pythonhosted.org/packages/56/da/be284a55c5619bda891a89c27dfd59324a2c6a14d755cf6aac6960ceebeb/coverage-7.15.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:7e8f27131dc7cd53de2c137dd207b3720919320b3c20d499dc30aa9ee6173287", size = 252093, upload-time = "2026-07-15T18:53:44.271Z" }, + { url = "https://files.pythonhosted.org/packages/d4/53/ee112da833ddd77b73c6d781a98029b45b584b136615b4900ed0569f887e/coverage-7.15.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:728a33676d4c3f0db977990a4bd421dcaa3be3e53b5b6273036fff6666008e89", size = 248552, upload-time = "2026-07-15T18:53:45.7Z" }, + { url = "https://files.pythonhosted.org/packages/82/6a/802cfc802e9113494c80bf3f284cd4d72faeb1f24e244f61046af364f2ca/coverage-7.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29c052f7c83ccfcc5c577eaae025d2e4a9bb80daf03c0ac31c996e83b000ce88", size = 249154, upload-time = "2026-07-15T18:53:47.256Z" }, + { url = "https://files.pythonhosted.org/packages/2c/65/529808e91d651147edae408fd9e894abc3b8cad7f3e594bbc36719a3e13a/coverage-7.15.2-cp310-cp310-win32.whl", hash = "sha256:1268ac8fb9ddcd783d3948dbabaf80a5d53bfdaa0575e873e2139a692f797443", size = 223334, upload-time = "2026-07-15T18:53:48.768Z" }, + { url = "https://files.pythonhosted.org/packages/68/0f/0e1829d7001130876dfbc0b4e1c737ea7c155b809e3e4a98a0aa268e2369/coverage-7.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:9f4432898c4bf2fba0435bbe35dd4437d7264565e5a88a21f5b49d8662a6b629", size = 223959, upload-time = "2026-07-15T18:53:50.429Z" }, + { url = "https://files.pythonhosted.org/packages/7d/3a/54536704f507d4573bf9161c4d0dd3dd59b6d85e48c664e901b6844d8e33/coverage-7.15.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f1ec6f304b156669cfde653b4e9a953f5de87e247ea02ac599bce0ab2744036", size = 221414, upload-time = "2026-07-15T18:53:51.941Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d9/8ba925d29743e3577b21e4d8c11a702b76bc93c41e7fdfd1177af63d4b8d/coverage-7.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d3361879d736f469f45723c11ea1a5bbdaf1f6928f0e632c940378b5aa9b660", size = 221913, upload-time = "2026-07-15T18:53:53.682Z" }, + { url = "https://files.pythonhosted.org/packages/09/54/a855f3aa0187f2b431ade4e4791b77b56282cfb5d201c83ec26a31b5b36a/coverage-7.15.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c6a98d698f9e2c8008d0370ec7fc452ebfcc530002ae2d0061170d768b992589", size = 252332, upload-time = "2026-07-15T18:53:55.467Z" }, + { url = "https://files.pythonhosted.org/packages/8e/d3/13ac97b4370640ba3452fc8559b06cc2f479ce3ba4a0b632a73e44c38a7d/coverage-7.15.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d50dd325e18ec25bfcc10cd7f99b04df1ab9ec76b0918c260e60817ad0643dee", size = 254243, upload-time = "2026-07-15T18:53:57.055Z" }, + { url = "https://files.pythonhosted.org/packages/88/83/5eca144942d8d0659d3f55176517f4a59cdc65eefd17146a0770935a3ebd/coverage-7.15.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67d7602480a47bdf5b675635403625553ebaa70d5a62a657c035149fd401cea0", size = 256352, upload-time = "2026-07-15T18:53:58.83Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ba/d3db2e01a50fc88cdb4c0f19542bcf6f61489e34dc9aa3538413e2459a38/coverage-7.15.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cee0f89f4767a6057c8fbf168f8135f18be651300496086bd873e3189fed0487", size = 258313, upload-time = "2026-07-15T18:54:00.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/b3/aba83416e9177df28e5186d856c19158c59fc0e7e814aaa61a4a2354ad1b/coverage-7.15.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a29ec5305a7335aacee2d799e3422e91e1c8a12474986e2b3b07e315c91be82f", size = 252449, upload-time = "2026-07-15T18:54:02.456Z" }, + { url = "https://files.pythonhosted.org/packages/6a/a5/4b00ecac0194431ab451b0f6710f8e2517d04cef60f821b14dec4637d575/coverage-7.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:48ccc6395958eda89093ecdc35644c86f23a8b23a7f4d44958812b721aad67c1", size = 254043, upload-time = "2026-07-15T18:54:04.072Z" }, + { url = "https://files.pythonhosted.org/packages/75/b6/cfa209b4313ee7f1b34da47efcd789ea51c024ad35af390e00f5a3c10a2e/coverage-7.15.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:81f382c5a94b434ec1f6da607edb904c76d7212e618cd4d1bc9f97bed4120ef5", size = 252107, upload-time = "2026-07-15T18:54:06.745Z" }, + { url = "https://files.pythonhosted.org/packages/36/67/e8cac5a6954038c98d7fe7eb9802afe7ab3ecb637bb7cc00e69b4148b56d/coverage-7.15.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bbc808daf4f5cd567af8075ecc72d21c6dfef9a254709a621a84c217c935ebc0", size = 255873, upload-time = "2026-07-15T18:54:08.48Z" }, + { url = "https://files.pythonhosted.org/packages/2c/92/395cca9f330a86c3fe3471d73e2c102116c4c58fdc619dbbc125c6e93a54/coverage-7.15.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a4c46b247b5d4b78f613bd89fea926d32b25c6cc61a50bd1e99ba310348f3dad", size = 251826, upload-time = "2026-07-15T18:54:10.083Z" }, + { url = "https://files.pythonhosted.org/packages/51/60/3e91b20295439652424f426b7086ec5bf4fbe3f604c73eda22b986c4fd6b/coverage-7.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:094dd37f3ef7b2da8b068b583d1f4c40f91c65197e16c52a71962d5d537fc5db", size = 252735, upload-time = "2026-07-15T18:54:11.878Z" }, + { url = "https://files.pythonhosted.org/packages/a5/eb/8c07839005e5e3c6b3877d3a6e2a80ce766589f31dd2b6882b78d59a7b8c/coverage-7.15.2-cp311-cp311-win32.whl", hash = "sha256:a63b9e190711134d581c4d703df5df09851b1acf99792c7aacbbe9f41f0283c9", size = 223500, upload-time = "2026-07-15T18:54:13.525Z" }, + { url = "https://files.pythonhosted.org/packages/2e/98/59d83c257cd59f0fbaf9d9ddb26b744a576760dfd1ae16e516408894a02b/coverage-7.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:8bb9f4b4279187560796a4cdaca3b0a93dd97e48ee667df005f4ed9a97403688", size = 223973, upload-time = "2026-07-15T18:54:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/ea/09/2d285c8bef5c4f695d120c1c96dc11715638aa8e134069f210bb6a62a9fe/coverage-7.15.2-cp311-cp311-win_arm64.whl", hash = "sha256:8c726b232659cbd2ae57ade46509eb068c9bd7a06df9fcbff6fe484870006934", size = 223519, upload-time = "2026-07-15T18:54:16.803Z" }, + { url = "https://files.pythonhosted.org/packages/6a/50/eb5bf42e531611a9f8d272556b1ed4de503f84a91413584094487cf69f8f/coverage-7.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1adac78e5abc7c5438f7a209c9ca69d06542f0bf481d728b6989ea80b813fdf9", size = 221587, upload-time = "2026-07-15T18:54:18.439Z" }, + { url = "https://files.pythonhosted.org/packages/06/d1/da99af464c335d4e023a6efcd7ec30f63b88a43c93745154ab74ffb31cea/coverage-7.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b868acc62aa5de3be7a9d05c2333bf8359ca987e43f9cb30ff8fbda6a024ab73", size = 221943, upload-time = "2026-07-15T18:54:20.062Z" }, + { url = "https://files.pythonhosted.org/packages/5b/8a/13c42723d61ca447eafa18732e8141dd6a63f2732e1c7e1502c182dd88d7/coverage-7.15.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6f6966fc30e6f06ca8f98fb0ce51eda6b111b3ee8d066a8b1ec9e77fa06ab55d", size = 253450, upload-time = "2026-07-15T18:54:21.765Z" }, + { url = "https://files.pythonhosted.org/packages/d7/29/99021303f98fbdcb63504b4d07bea4cc025b9b2dd907c4f07c85d50a0dab/coverage-7.15.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:68af907f595ab01a78f794932ff3bdf929c316d3000810d38dbc247129e26f8b", size = 256187, upload-time = "2026-07-15T18:54:23.4Z" }, + { url = "https://files.pythonhosted.org/packages/f9/a8/fd503715ed6ca9c5d742923aa5209257340b367a867b2ced0c7d4ba8a0b9/coverage-7.15.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:afa29e2eff3d5729267e2cb2fd4ce9d61c952932fb2694e34ccb5d9540c6a296", size = 257301, upload-time = "2026-07-15T18:54:25.183Z" }, + { url = "https://files.pythonhosted.org/packages/da/40/3f4b8fb409810036ebc2857d36adc0498c6e957b5df0290c5036b2e143f1/coverage-7.15.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bbf44513ceb1589e31948e20eafbde9deaface90e1a1afa5f5f77b4423d17ce6", size = 259562, upload-time = "2026-07-15T18:54:27.204Z" }, + { url = "https://files.pythonhosted.org/packages/0b/8a/9bdffbef47db77cce3d6b02a28f7e919b19f0106c4b080c2c2246040f885/coverage-7.15.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9deddf09eecb717b7f980414b43d90a5b22ff3967d2949ab29cb0aa83d9e9098", size = 253841, upload-time = "2026-07-15T18:54:29.134Z" }, + { url = "https://files.pythonhosted.org/packages/1b/1e/9031efde019d31a06646261fce6dfc5c3c74e951e27a71e5c9a424563178/coverage-7.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae901f7e55ba405c84ee1cab3d3e962e4e871e4a2bcb9c90911adbd69b42ac5a", size = 255221, upload-time = "2026-07-15T18:54:31.142Z" }, + { url = "https://files.pythonhosted.org/packages/56/db/787acde872389fc84a9ef9d8cd1ccc658e391ab4cb5b28092a714426a394/coverage-7.15.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a0f47002c6eeb7c280228467a4cb0cc15ca2103a8421b986b2d3ec04a0f9bd8b", size = 253366, upload-time = "2026-07-15T18:54:32.886Z" }, + { url = "https://files.pythonhosted.org/packages/2f/9b/6f57bc4b93c842eef1695f8cdaf2318e35e7ba54f5ba80d84be213ab7858/coverage-7.15.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1cd7a5beb7af3e864a13b1f0fb26efd3695da43ef0daf71e586adfffaf34d5b2", size = 257434, upload-time = "2026-07-15T18:54:34.7Z" }, + { url = "https://files.pythonhosted.org/packages/88/26/b3186a21b2acc83e451118978905c81c7072c3333707804db09a78c096a2/coverage-7.15.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:97a5c5457a9fb1d6c4e06cfb5dc835871fbfb6a6a51addc9e925bdeff5ef7440", size = 252935, upload-time = "2026-07-15T18:54:36.548Z" }, + { url = "https://files.pythonhosted.org/packages/20/c2/c9f3376b2e717ea69ed7a6e9a5fcab968fb0b290db6cf4bd9a1fc7541b75/coverage-7.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0901cfe6c13bcd2302da4f83e884555d2a22bda6e4c476f09ef204ba20ca536e", size = 254807, upload-time = "2026-07-15T18:54:38.296Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e1/dfc15401f4a8aaeb486e1ba3e9e3c40522a6e38bd0ecf0b3f29cb8082957/coverage-7.15.2-cp312-cp312-win32.whl", hash = "sha256:b171bdd71cb7ff792bf32e376173b0ace7e7963e7e57c58dfc42063a6a7174cd", size = 223641, upload-time = "2026-07-15T18:54:40.103Z" }, + { url = "https://files.pythonhosted.org/packages/91/40/81b6d809d320cd366ec5bdf8176575e897dcb8efe7fb4b489ef9e93e4d13/coverage-7.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:582edc45c2040543fef83341be23c43024a3ab3ae0c2d8bc498a06282905ad40", size = 224172, upload-time = "2026-07-15T18:54:41.882Z" }, + { url = "https://files.pythonhosted.org/packages/ef/28/9f14ec438149f7de557f45518f09b4a7917b795cc37083aa7db482693f8c/coverage-7.15.2-cp312-cp312-win_arm64.whl", hash = "sha256:a638db90c61cd219aeee65e83a24fdaa57269a741ae0cf773309208ac862cee3", size = 223556, upload-time = "2026-07-15T18:54:43.674Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d5/f8c838e6b7282976f7c918884b792df7a0c42c5bba5d99c60ad2d221d56d/coverage-7.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1121caa19159a38b5463eaae4b1e1fde81e525b15ecc5e000cd5b1a108f743a8", size = 221606, upload-time = "2026-07-15T18:54:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/bf/37/97c926376364f66298cc44893b89cdf17b8bc406376497c4061ae4b8a8ff/coverage-7.15.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a300c6934e0989c327b9e8a1e110329da4641149f872bbe9f70168be66da76c1", size = 221982, upload-time = "2026-07-15T18:54:47.341Z" }, + { url = "https://files.pythonhosted.org/packages/b7/30/a36050a6e83c2135ee0776f452ca3948224befc6d7f26acecc082d0c106a/coverage-7.15.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2617f8799d268fabdeef42a7e89ac3a23e1deee9025427db2df970f99a89a578", size = 252972, upload-time = "2026-07-15T18:54:49.2Z" }, + { url = "https://files.pythonhosted.org/packages/31/d3/06b5f1daf95f0f15ab05bd75f26ba5f3c8b33d0bb72f3aaa3cf41d1bad3a/coverage-7.15.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7dc2950a2992cd676d35c20ae63522836deeb034f08874699d14068710af3dc1", size = 255569, upload-time = "2026-07-15T18:54:51.098Z" }, + { url = "https://files.pythonhosted.org/packages/81/1c/9afb3f8de2b8d36960391c48559a2e3ff96594b58099f115921549ea8d0d/coverage-7.15.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e36686f7a442185db2400b3df171aac520869faf9deb59df687d28659eda2a6", size = 256806, upload-time = "2026-07-15T18:54:53.145Z" }, + { url = "https://files.pythonhosted.org/packages/64/d8/b989f96061a5e32d82fddd1b1b9ff48a7c8f8ae7606f0e80fd9de54b1e33/coverage-7.15.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d29ca7bd67af6e12e74632d65f026eabc1364da5c254494cd914446a28a3ef7", size = 258936, upload-time = "2026-07-15T18:54:55.015Z" }, + { url = "https://files.pythonhosted.org/packages/b8/fa/f99771f5110457c7b511c1935ca49ddf288218eaa84322e028b9334146ae/coverage-7.15.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:db9c8438057e5b0f6a22a0af99c0c1d26b57fbbdbd1be5861ddb8f897fcc3a2d", size = 253178, upload-time = "2026-07-15T18:54:57.527Z" }, + { url = "https://files.pythonhosted.org/packages/f6/96/c098a6044d119c751ceede7be91035fa8310170ec24a6523aff72f0a5793/coverage-7.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:63022c4c8dec1d0342f05c3ede99842fe3d007689acc45e86f123a1746e4a026", size = 254934, upload-time = "2026-07-15T18:54:59.41Z" }, + { url = "https://files.pythonhosted.org/packages/b2/a2/1457b3a7a50c8d77500103b97a046db863e2f59a1cf6d2f814595f349885/coverage-7.15.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6c0be82b4d4aa5b2704e08518e2252f3e3d110164bcca826816801052e48a7aa", size = 252898, upload-time = "2026-07-15T18:55:01.338Z" }, + { url = "https://files.pythonhosted.org/packages/6c/0e/76958874c471ecfcdde0d2b2747bb2c61bdbf34a40636f4ce9db9923e643/coverage-7.15.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4510fb9cdf6bb02dfa6af0be4a534b8102d086e22e4a33f8836df663da3d660d", size = 257056, upload-time = "2026-07-15T18:55:03.243Z" }, + { url = "https://files.pythonhosted.org/packages/7c/7c/3d7c4e3bf58baa40327dc7edc2272b17cf02299366d52763db1b0ca1556a/coverage-7.15.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:42ec3d989421b174a2ab607c1539f24127ad362757b7f1c0c0d7a2993f7eb37b", size = 252718, upload-time = "2026-07-15T18:55:05.029Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b8/1cecffed9ce14fb25be9ba42d37b6bb61485c9a3ddd43cd3dde36b6087d8/coverage-7.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8f91bce78e32343af184c3b7fa28fcf5a9e2641f4b6623d392038f804939188", size = 254490, upload-time = "2026-07-15T18:55:06.889Z" }, + { url = "https://files.pythonhosted.org/packages/6c/2c/42984561bc7f4c045dca67516a0c50ee5ef8d84352dbeb5559dc86c4823e/coverage-7.15.2-cp313-cp313-win32.whl", hash = "sha256:434e68d531858205895eb0d74b73d20b84260de426387d53c422a5acda2cf050", size = 223647, upload-time = "2026-07-15T18:55:08.941Z" }, + { url = "https://files.pythonhosted.org/packages/41/9f/39c7c9245efc583beddf89a87683574e663ed93637f3afb6cd7b88405676/coverage-7.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:26c3b04a6377fd7c09800921fa934e3a17c0020439cd59df73e73ae1d4b6a78c", size = 224190, upload-time = "2026-07-15T18:55:10.789Z" }, + { url = "https://files.pythonhosted.org/packages/c7/de/3a2883cf8a213659280ef4b403059e17a9acaeb7fc7fd4105e1226ff2e6d/coverage-7.15.2-cp313-cp313-win_arm64.whl", hash = "sha256:3ed010aa1b69cda8e827aabfca9866216c980e2dca82ab9a78c5f83689964c8b", size = 223583, upload-time = "2026-07-15T18:55:12.678Z" }, + { url = "https://files.pythonhosted.org/packages/81/5f/aed265fd7a3551a394f36dfe41868aee709b7f95db4052205b4ad1563ac3/coverage-7.15.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:40f633c5c5fc783732f6312280122e859538fa24461235597c13d803ea9a108a", size = 221650, upload-time = "2026-07-15T18:55:14.527Z" }, + { url = "https://files.pythonhosted.org/packages/6b/2c/222ba12a545189017120f8eddfc1a0bd4616b47d5d4a8d99421edb2fe4c6/coverage-7.15.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:075560438765b7a2ef43bf7aa7758661b53d889df47f062a31bda6c1ade553a2", size = 221988, upload-time = "2026-07-15T18:55:16.674Z" }, + { url = "https://files.pythonhosted.org/packages/aa/38/304b5877ab46e6c290b4292cfcf3fe28245f0e5597cad7f6acc91fc7e0a4/coverage-7.15.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:25fd15dd40a0a2c51a500d664ca29053c09c3259d998407bf982b6e114696138", size = 253029, upload-time = "2026-07-15T18:55:18.856Z" }, + { url = "https://files.pythonhosted.org/packages/6c/58/821b533b8db9e44cf1d8a97bd525149ced40dde1d0093da02cb78e715244/coverage-7.15.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b9a6367e4aff723e8ee8190836836124284e8fcd4265e307c844010cfa074f3f", size = 255536, upload-time = "2026-07-15T18:55:21.027Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f2/7aa06604c389d32ea7f0a6a988359a7eafc3cd3f8e7bc2e88cd2fdf0b877/coverage-7.15.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9854ca62c152874b2060772503535be2e8f53f70b8aaa7686b094888d872f984", size = 256881, upload-time = "2026-07-15T18:55:23.125Z" }, + { url = "https://files.pythonhosted.org/packages/a2/4f/1ef342339c7916d0096bc5888cc0f653882cc7bc8f897d5cb89143287c9b/coverage-7.15.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:913b6c56e110da40e035bbd168353bf7aaa2544a5eaccea5d98a4629aac156c7", size = 259196, upload-time = "2026-07-15T18:55:25.099Z" }, + { url = "https://files.pythonhosted.org/packages/fe/f4/7ed055d7a9c5ec13b161773a115a5ccc6b0081d568c31fad830806306cc7/coverage-7.15.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aaccad4129d735a8a4d526f26929894c9a4e8ef7034566f210b176749d6906e3", size = 253036, upload-time = "2026-07-15T18:55:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/14/79/ea82cca18c242a3a38b6c017da39726aa62dcb64aa635abf79b92009975c/coverage-7.15.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a164b50081fc7357331c4024ef4d17b78ba325f8380d05f5a69599a7e05257ee", size = 254887, upload-time = "2026-07-15T18:55:29.084Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ba/a136db3c0d9562b00e10b72540dbf3a33cd3bc5b95060c9308e247494623/coverage-7.15.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bfd341ccf78128e72c094bc70cc25b3ef309c33c7c2c66ba3ed4309549e02de1", size = 252852, upload-time = "2026-07-15T18:55:31.184Z" }, + { url = "https://files.pythonhosted.org/packages/17/17/ea334246b16b7d059953fad6fdefa11e33c68efbd3fe37b1098120a1fac2/coverage-7.15.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1473b3ba8e7ee0f076117b1a72c23f579a2b9e2bb742f48a8d86ea27ca93f91a", size = 257128, upload-time = "2026-07-15T18:55:33.163Z" }, + { url = "https://files.pythonhosted.org/packages/ed/c3/074fb66d46d607855f710876b117cbda562c5ab08363528e78820449f937/coverage-7.15.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:17c432b5f73ad52ef46fb06019f6fa7c66ce381961cf0f7dfd1d3a4bd3a98145", size = 252668, upload-time = "2026-07-15T18:55:35.063Z" }, + { url = "https://files.pythonhosted.org/packages/e1/c1/f620850ada9b36435921c9a3a8057013422b1d964eb4bf37fe138724d192/coverage-7.15.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:77f0ef5011df53a4bd1b35211ab122287f8d9b8d7aa1c4553e5c2deb24b1d446", size = 254325, upload-time = "2026-07-15T18:55:37.125Z" }, + { url = "https://files.pythonhosted.org/packages/cc/31/a729ca3689404493af82ef8e6ff70bd88bdda8da89aeef6ca9b387aeb2b4/coverage-7.15.2-cp314-cp314-win32.whl", hash = "sha256:f653e5d7248c1191ec988a85c72edeab46c3ff44f90639a4ed4874ec0be90243", size = 223844, upload-time = "2026-07-15T18:55:39.078Z" }, + { url = "https://files.pythonhosted.org/packages/c6/83/5d809dc808fb1698c671f3e372259bb9158e64b7ea526fc6ab7de64de9fe/coverage-7.15.2-cp314-cp314-win_amd64.whl", hash = "sha256:9911f31aad8906abe337c271343485cf20df5e70df5d2f57f9f136e7b55f26bc", size = 224331, upload-time = "2026-07-15T18:55:41.346Z" }, + { url = "https://files.pythonhosted.org/packages/16/4e/35e488548e952795829e129995c4174df33bf432b591d1aa42c8d9e4e7ad/coverage-7.15.2-cp314-cp314-win_arm64.whl", hash = "sha256:e38def96ad59853824c97953fdcd2c320a84ba3ce99b417db78af8bb6c3db635", size = 223760, upload-time = "2026-07-15T18:55:43.518Z" }, + { url = "https://files.pythonhosted.org/packages/ed/49/dd2c86cd6374038f6e415fb5bfb86db5218553209c081384a020369dee79/coverage-7.15.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:835ec4e20b45f0a7f63ed78f94065aca00de033403df8377bfe8b9c6abc0a7be", size = 222384, upload-time = "2026-07-15T18:55:45.569Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/173ff17a1c0808e5a438f549f6f145d5ac7528f2791310b63523e3200ac7/coverage-7.15.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7466cc7ab6dc0db871d264bf99e8779f0917ee63d40730af0552f71535a6e072", size = 222647, upload-time = "2026-07-15T18:55:47.544Z" }, + { url = "https://files.pythonhosted.org/packages/84/f8/b8cba872162356fb44ac79c10309d987206a4461e32072fc29228dad7331/coverage-7.15.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e370c12133095ff18432de8c044962be85a5a96d90c6fcbce8e17e76236d2328", size = 264013, upload-time = "2026-07-15T18:55:49.768Z" }, + { url = "https://files.pythonhosted.org/packages/ee/67/a807a7586d0b8cae485308ddd55756f0806c92f8e0b411bacbf23c48edf3/coverage-7.15.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fe41909c9515c3bfdb5f02c4d1f857dba322d9a9a1178069b91eea77889df63a", size = 266135, upload-time = "2026-07-15T18:55:51.941Z" }, + { url = "https://files.pythonhosted.org/packages/ce/67/cd78771dc985f7e4ebdcc82b1a96d9a932af9e806f01f2f91a89f4c72e80/coverage-7.15.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6aa28cfb6488e5453b5b762d65f73aa586380f6693a04d58078ce228a29b06c0", size = 268555, upload-time = "2026-07-15T18:55:54.065Z" }, + { url = "https://files.pythonhosted.org/packages/18/3e/10134cf81275188c58568f324fc74aedff32c63ca4d5bbc513a91944a6f0/coverage-7.15.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcc0aae933921d03096f53b0b03eeb702129fd406dee59f08d2efacc68681fa5", size = 269674, upload-time = "2026-07-15T18:55:56.066Z" }, + { url = "https://files.pythonhosted.org/packages/75/4a/771b77de446cba985dc414bbc5844bd21604da05dbc044286df8318a48a7/coverage-7.15.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7c63387e21ab21f512c69c9756a8c7dadd322c7275edb064064433c9a09c3743", size = 263101, upload-time = "2026-07-15T18:55:58.107Z" }, + { url = "https://files.pythonhosted.org/packages/5f/b5/70a7011da15f4071943361183aefa27847f3e3aec4fd335f1cb3d3a622b1/coverage-7.15.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e55510bc98ae943cece9e667a6c0fe94c6a92913720dea34243657a17993d0c", size = 266007, upload-time = "2026-07-15T18:56:00.468Z" }, + { url = "https://files.pythonhosted.org/packages/b4/0d/f9547e804ce7ad49646ffeffac26699510efbe6c0f751b66fdc960c4e825/coverage-7.15.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2ff08701be2d1556fc78b326c80a3e8042da09352ecb3819105f8e386c8a3071", size = 263611, upload-time = "2026-07-15T18:56:02.615Z" }, + { url = "https://files.pythonhosted.org/packages/ac/59/f576a396659c0efd351f5c1544f67c3560e89c7761cabf7f65e412beeda5/coverage-7.15.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:38c9518b7103826c403a461544e3c2e77151e8676d06eaed85911a97e962584a", size = 267344, upload-time = "2026-07-15T18:56:04.622Z" }, + { url = "https://files.pythonhosted.org/packages/7c/5d/c2e4fce3579c0cb635024293f1a32bbe26df101b3e3a69f22243d1352b6c/coverage-7.15.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:dee88b1ed88587abd8c0269a1fc1f4cc77f7750d1dfde2869e2a123af420e67d", size = 262456, upload-time = "2026-07-15T18:56:06.641Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/956287d69436b66094bc4b57ac2da71e43bfd2a5524e958900b9f582fcf8/coverage-7.15.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fbeeeecea279727f8ac16c8e1133ddfeee793e985c86ae343d6a5ce744eef8c", size = 264771, upload-time = "2026-07-15T18:56:08.795Z" }, + { url = "https://files.pythonhosted.org/packages/2c/5a/6f979530c2734c575de77cf58f5f28d51f7123a94b5030fd9156fe5f363c/coverage-7.15.2-cp314-cp314t-win32.whl", hash = "sha256:cb0fddaa6884be6aae36ced9544b5e90f7d5f03845a2853bf47a14953a4e8688", size = 224151, upload-time = "2026-07-15T18:56:10.856Z" }, + { url = "https://files.pythonhosted.org/packages/54/7e/27f6b2a74d484742f4017553e710b01e396b23d809df3e95ca0bb9a2824b/coverage-7.15.2-cp314-cp314t-win_amd64.whl", hash = "sha256:77f091ea3a9cc611cd29f433565476bc1936c084ac8eee00ea0e7e70c27e4199", size = 224981, upload-time = "2026-07-15T18:56:12.928Z" }, + { url = "https://files.pythonhosted.org/packages/b1/48/284863423aa474240f6842bd00d680da22f4e6ea2e466618ef7c9c9e69a9/coverage-7.15.2-cp314-cp314t-win_arm64.whl", hash = "sha256:6fc448c377d6eeb00a47c673494bd9bae29280ca53987e1869e67ebedfe20658", size = 224294, upload-time = "2026-07-15T18:56:15.156Z" }, + { url = "https://files.pythonhosted.org/packages/ec/82/32e3bd191d498e64f6f911ad55d14006a0861e54869d2d32452326399e65/coverage-7.15.2-py3-none-any.whl", hash = "sha256:eb6bcae8d1a9d305351ecb108232441d11c5cfe9de840a04388ba5d2db8d735c", size = 213375, upload-time = "2026-07-15T18:56:17.305Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "distlib" +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/02/bd72be9134d25ed783ecbbc38a539ffaefbf90c78418c7fb7229600dbac7/distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed", size = 615141, upload-time = "2026-06-12T08:04:52.847Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "filelock" +version = "3.32.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/80/8232b582c4b318b817cf1274ba74976b07b34d35ef439b3eb948f98645a1/filelock-3.32.0.tar.gz", hash = "sha256:7be2ad23a14607ccc71808e68fe30848aeace7058ace17852f68e2a68e310402", size = 213757, upload-time = "2026-07-21T13:17:42.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/79/b4c714bef36bc4ec2beeae1e0c124f0223888cd8c6feb1cdc56038116920/filelock-3.32.0-py3-none-any.whl", hash = "sha256:d396bea984af47333ef05e50eae7eff88c84256de6112aea0ec48a233c064fe3", size = 97732, upload-time = "2026-07-21T13:17:41.55Z" }, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "griffelib" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/e4/8d187ea29c2e30b3a09505c567513077d6117861bde1fbd997a167f262ec/griffelib-2.1.0.tar.gz", hash = "sha256:762a186d2c6fd6794d4ea20d428d597ffb857cb56b66421651cbba15bdd5e813", size = 216234, upload-time = "2026-06-19T12:05:42.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/d3/5268aeabf2ad82658c4e2ff3a060648d0f02f3926cb53247c0e4d0dab49e/griffelib-2.1.0-py3-none-any.whl", hash = "sha256:cc7b3d2d2865ad0b909fcc38086e3f554b5ea7acbaa7bbb7ecaa3f5dfb7d9f00", size = 142560, upload-time = "2026-06-19T12:05:38.742Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "identify" +version = "2.6.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +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/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588, upload-time = "2026-02-10T15:23:55.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530, upload-time = "2026-02-10T15:23:53.817Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/25/b3cccb187655b9393572bde9b09261d267c3bf2f2cdabe347673be5976a6/mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1", size = 11047, upload-time = "2026-03-10T02:46:33.632Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650", size = 9555, upload-time = "2026-03-10T02:46:32.256Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.7.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/cd/c05d3a530ba7934f144fb45f7203cd236adc25c7bdcc34673d202f4b0278/mkdocs_material-9.7.7.tar.gz", hash = "sha256:c0649c065b1b0512d60aad8c10f947f8e455284475239b364b610f2deb4d0855", size = 4097923, upload-time = "2026-07-17T16:21:33.156Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/21/17c1bc9e6f47c972ad66fb2ac2568f99f90f1207eeb6fc3b34d094dba7b5/mkdocs_material-9.7.7-py3-none-any.whl", hash = "sha256:8ea9bb1737a5b524a5f9dcf2e1b4ebda8274ae3008aa7845720a97083bef708f", size = 9305438, upload-time = "2026-07-17T16:21:30.017Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "1.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/71/f85bdf13355073ae15a7375f09879375a830553552e58c1c4b7e0bbc5c8b/mkdocstrings-1.0.6.tar.gz", hash = "sha256:a0b8c2bdd29a6416c80d717aa369bbf7831946bd9f23c2a66db1b1dbe7693dbd", size = 100649, upload-time = "2026-07-11T19:38:05.732Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/5b/4c1902e8bdd5c4db63284e9d101dece4038d4025d6d88850ffe0a1578980/mkdocstrings-1.0.6-py3-none-any.whl", hash = "sha256:2703708697487d1b6d6d7b412e176fa436edf120c1bf81dc9e126b12d00893c7", size = 35787, upload-time = "2026-07-11T19:38:04.417Z" }, +] + +[package.optional-dependencies] +python = [ + { name = "mkdocstrings-python" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffelib" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/b6/e858701499d57eee8b3fd8e78168083956c6683ddbe727b46758b19e1119/mkdocstrings_python-2.0.5.tar.gz", hash = "sha256:3a4d92556ad39637e88af94a5374213af9a8e3040c3824ceaed04b486c017594", size = 199578, upload-time = "2026-06-19T10:41:08.868Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/fc/10ab7e80650a9c9e8f4f1105f8c8e73567f88ed0c06ada589ab81d38687c/mkdocstrings_python-2.0.5-py3-none-any.whl", hash = "sha256:30c837bbff016549f659fcba6539ac351303f0fd7e713c89a040611072236e9d", size = 104951, upload-time = "2026-06-19T10:41:07.378Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "paydunya" +version = "2.0.0" +source = { editable = "." } +dependencies = [ + { name = "httpx" }, +] + +[package.dev-dependencies] +dev = [ + { name = "mkdocs-material" }, + { name = "mkdocstrings", extra = ["python"] }, + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-httpx" }, + { name = "ruff" }, + { name = "tox" }, + { name = "tox-uv" }, +] +docs = [ + { name = "mkdocs-material" }, + { name = "mkdocstrings", extra = ["python"] }, +] + +[package.metadata] +requires-dist = [{ name = "httpx", specifier = ">=0.27" }] + +[package.metadata.requires-dev] +dev = [ + { name = "mkdocs-material", specifier = ">=9.5" }, + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.25" }, + { name = "pre-commit", specifier = ">=3.7" }, + { name = "pytest", specifier = ">=8.2" }, + { name = "pytest-cov", specifier = ">=5.0" }, + { name = "pytest-httpx", specifier = ">=0.30" }, + { name = "ruff", specifier = ">=0.5" }, + { name = "tox", specifier = ">=4.15" }, + { name = "tox-uv", specifier = ">=1.11" }, +] +docs = [ + { name = "mkdocs-material", specifier = ">=9.5" }, + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.25" }, +] + +[[package]] +name = "platformdirs" +version = "4.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/78/9b/560e4be8e26f6fd133a03630a8df0c663b9e8d61b4ade152b72005aec83b/platformdirs-4.11.0.tar.gz", hash = "sha256:0555d18370482847566ffabcaa53ad7c6c1c29f195989ae1ed634a05f76ea1e0", size = 31953, upload-time = "2026-07-21T13:09:36.565Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/68/d8d58938dfb1370b266a1a729e6d77a985be23689a0496498ee17b2cbf90/platformdirs-4.11.0-py3-none-any.whl", hash = "sha256:360ccded2b7fce0af0ff80cc8f5942a1c5d99b0e856033acb030bfc634709e74", size = 23247, upload-time = "2026-07-21T13:09:35.422Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/3a/ddb78f32a0814e66b18a099377a106a2dcdce92d86a034d69d65df9b256e/pre_commit-4.6.1.tar.gz", hash = "sha256:03e809865c7d178b9979d06c761fcbfe6808fdaded8581a745bb110e52050421", size = 198646, upload-time = "2026-07-21T20:56:58.225Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/49/bc925106abcdac498074f2cbe6137e94e09f418dd2b7775df5b577dc0313/pre_commit-4.6.1-py2.py3-none-any.whl", hash = "sha256:0e3b2942510d1fb34eec167a3ec57331bf8442122f1153a9fb8b58f5c49b2717", size = 226186, upload-time = "2026-07-21T20:56:57.064Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pymdown-extensions" +version = "11.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/a9/5f0c535ba3b08fe09270c16808e053a968868242ecbd5676d4e3a488bf28/pymdown_extensions-11.0.1.tar.gz", hash = "sha256:dd2905ae6fc5b75582fafb139a1266ffc754705efa902aa50067fa7ff4f94ec0", size = 857113, upload-time = "2026-07-02T17:59:22.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/54/da572c98c0b77626a91b5d3b89f0231d8bff5125c225420908632f8b342d/pymdown_extensions-11.0.1-py3-none-any.whl", hash = "sha256:db3943a62bab7e03af1364f0c4083e64b91fb097675a4b6cceccfbe9a77e5eb2", size = 269455, upload-time = "2026-07-02T17:59:21.271Z" }, +] + +[[package]] +name = "pyproject-api" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/bd/2f985c12bf33fdd8637e3a8f9418d6806f177601dee7c4924d0b2bb28650/pyproject_api-1.11.0.tar.gz", hash = "sha256:b8807d85a293e6c9f133e6575946fed45f1d42b22d58c780b33aa2421a799549", size = 23787, upload-time = "2026-07-21T13:09:33.744Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/6a/2822ee12bafe87af8f6cc620f7d1f126e77f82ce56ba888b94a9af5a979c/pyproject_api-1.11.0-py3-none-any.whl", hash = "sha256:860060c8832dce983b5eec6f41c4c43eb3ec06ff7332387a63acdf5ca27b68d8", size = 13275, upload-time = "2026-07-21T13:09:32.559Z" }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] + +[[package]] +name = "pytest-httpx" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/42/f53c58570e80d503ade9dd42ce57f2915d14bcbe25f6308138143950d1d6/pytest_httpx-0.36.2.tar.gz", hash = "sha256:05a56527484f7f4e8c856419ea379b8dc359c36801c4992fdb330f294c690356", size = 57683, upload-time = "2026-04-09T13:57:19.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl", hash = "sha256:d42ebd5679442dc7bfb0c48e0767b6562e9bc4534d805127b0084171886a5e22", size = 20315, upload-time = "2026-04-09T13:57:18.587Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-discovery" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/51/276f964496a5714ab9f320896195639086881c2b39c03b5ad13de84acbb8/python_discovery-1.5.0.tar.gz", hash = "sha256:3e014c6327154d3dda27939a9a0dc9c5c000439f1906d3f303b48f984bd2ecef", size = 72483, upload-time = "2026-07-21T13:14:14.641Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/7b/14882602ddee241d7984a742fcb423cb4a30fb0d6efc546ac3129fba475a/python_discovery-1.5.0-py3-none-any.whl", hash = "sha256:70c4fc61b4e7404e44f01d6fc44a715c4d685ca6cea83d295922f05891877c98", size = 34205, upload-time = "2026-07-21T13:14:13.398Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/06/ae069393fc66e8ff33036d4b368003833bf6e88ccf182e17e7a2f1c754fd/ruff-0.15.22.tar.gz", hash = "sha256:3f15175b1fb580126f58285a5dae6b2ea89000136d980c64499211f116b54809", size = 4785063, upload-time = "2026-07-16T15:14:13.244Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/18/ee54b7ae1e121be7a28ea6da4b67564ebb0530e183a54415ab7e3bcd2c4e/ruff-0.15.22-py3-none-linux_armv6l.whl", hash = "sha256:44423e73493737f5e7c5b41d475483898ff37afcdae38bc3da5085e29af1c2d8", size = 10781258, upload-time = "2026-07-16T15:13:19.452Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d2/2520cb14761ddbeaf57642a76942fc36adcbdbe53b4532241995f6fc485c/ruff-0.15.22-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b82c6482946e9eda7ff2e091d25b8bad3f718684e1916d41bd56873cee05b697", size = 10999477, upload-time = "2026-07-16T15:13:23.318Z" }, + { url = "https://files.pythonhosted.org/packages/c9/10/74e53572aa758dfaa678c2a2646b5c5515d884b7ca56be4d2ce03ca4b560/ruff-0.15.22-py3-none-macosx_11_0_arm64.whl", hash = "sha256:11c1c715af53a09f714e011106bffc419751ec8232fcb5da42173284ea3fec6f", size = 10466716, upload-time = "2026-07-16T15:13:26.162Z" }, + { url = "https://files.pythonhosted.org/packages/1e/cc/44eaaf0844e028182f2d0a8f2190d0f359159aed0a9e5ab861d892f1ae2a/ruff-0.15.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:742a29cf29bddb7c8327895d6a10e0e6c5b38a96dd407af9b5d0857f809c0576", size = 10892644, upload-time = "2026-07-16T15:13:29.229Z" }, + { url = "https://files.pythonhosted.org/packages/9f/21/8edf559014d2b0f82beea19cfb713993ad802ccda16868769979c6090a84/ruff-0.15.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72af58b951b0ae395935ae79763dc349bc0eb706319d28f7a33ad2cfb3cfc178", size = 10576719, upload-time = "2026-07-16T15:13:32.35Z" }, + { url = "https://files.pythonhosted.org/packages/bf/1e/3a13abd392a3b50b62e5938a831f9ab6e588358cacad5c18545b716d2182/ruff-0.15.22-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d425005c1835eb24e2ee4161cb90e8db263415f4a71c8c72c33abaa6c0c224", size = 11376494, upload-time = "2026-07-16T15:13:35.958Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3e/422d3d95bcf04dd78e1aeac22184d4f9a8fb2c01865d39d44618484a0317/ruff-0.15.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b9b3f8779a4f08c969defc3c8c35abffaa757e601ed5ae66d6d1db6519969a", size = 12208370, upload-time = "2026-07-16T15:13:39.185Z" }, + { url = "https://files.pythonhosted.org/packages/1e/91/5d065a0e0a02bf4813f5119ad278462eed081d2b832eb7c021ade0ec9e65/ruff-0.15.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e0dd1b2e4d3d585f897a0d137cbf4eaf6223bef4e8ce34d6bb12556c5f9249e", size = 11581098, upload-time = "2026-07-16T15:13:42.132Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f9/a0d4871d12fae702eb1f41b686caf05f1f8b124dc6db6f784f53d74918fa/ruff-0.15.22-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365523eb91d9224e1bcb03b022fbf0facb8f9e23792a2c53d9d4b3924bdbdebb", size = 11399422, upload-time = "2026-07-16T15:13:45.2Z" }, + { url = "https://files.pythonhosted.org/packages/18/80/c843a5176cddbceb0b7e8dd41cf9993490796c1c469348d384f5a5c13c56/ruff-0.15.22-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fabfd168afdf29fee5be98b831efa9683c94d7c5a3b58b9ce5a2e38444589a74", size = 11381683, upload-time = "2026-07-16T15:13:48.46Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/8485de0ae92239438a36cfc51350db9b9e85c9ebdfaea91b18e422706662/ruff-0.15.22-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:225dbf095a87f1d9f90f5fd7924d2613ee452a75a4308c63a8f50f761787aa7c", size = 10850295, upload-time = "2026-07-16T15:13:51.655Z" }, + { url = "https://files.pythonhosted.org/packages/fa/91/24977ec2ec72eaf15e4394ace2959fdff2dd1e14f03e005e838023407169/ruff-0.15.22-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1877d63b9d24ed278744f1523fd11b85540566d54641f97c566d7d9dc5ca5296", size = 10579640, upload-time = "2026-07-16T15:13:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/9c/47/9b51216951974df1f263ac19da550d34252e0ed7218c25f10c5ef9ed7517/ruff-0.15.22-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1606c510bd7215680d32efab38965f7cdec3ef69f5170a3f4791404ffdd5262", size = 11105077, upload-time = "2026-07-16T15:13:57.915Z" }, + { url = "https://files.pythonhosted.org/packages/c2/47/20e9d4a3b8016778acea5fc32bb50d35d207500a17ddb529ffa6996feef8/ruff-0.15.22-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:630479b18625f5ffc373f77603a22a9f8ac0acd7ff0501178b5db28ec71e9c64", size = 11490980, upload-time = "2026-07-16T15:14:01.032Z" }, + { url = "https://files.pythonhosted.org/packages/4d/76/3f72d8fc38c1cb77b38c56a70da9d0c17700cc1cc50f9649c9d3c8f5ba71/ruff-0.15.22-py3-none-win32.whl", hash = "sha256:e5ba0e4a13fd14abbed2a77b517a3911290c6c6c59ef67784328d1668fab76cf", size = 10789165, upload-time = "2026-07-16T15:14:04.16Z" }, + { url = "https://files.pythonhosted.org/packages/cb/46/4965251734c2b6fcdca1b1b187d20bcac3af0ee5b083b89c910bb961ce3a/ruff-0.15.22-py3-none-win_amd64.whl", hash = "sha256:9be63ba1eb936acd2d1342fb8337c356353706fce233b2a15a09a97037e6acde", size = 11938297, upload-time = "2026-07-16T15:14:07.316Z" }, + { url = "https://files.pythonhosted.org/packages/57/c9/e69b1ff4c8b69093ef08b8919ab767af0569666865b39c30a8795d88d3c6/ruff-0.15.22-py3-none-win_arm64.whl", hash = "sha256:e1168075b72158510839f250027659cdd78476f40507dd517892304c41318661", size = 11298172, upload-time = "2026-07-16T15:14:10.51Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, + { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, + { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, + { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, + { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, + { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "tomli-w" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, +] + +[[package]] +name = "tox" +version = "4.58.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "colorama" }, + { name = "filelock" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "pluggy" }, + { name = "pyproject-api" }, + { name = "python-discovery" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "tomli-w" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/8e/4d2b1b2a81f4de1cd4e54fa40df1ab5f9bb88fe2e37461fc44aba8f9d302/tox-4.58.0.tar.gz", hash = "sha256:ab0b126a04dd56bc18e6d216386db09335247f2289b54cf534deb5c4ae3a8d2e", size = 296926, upload-time = "2026-07-21T13:10:36.622Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/3d/7ba55871e9d794d40b6c8424f2e5d1b267ea5d9a4bd2175e08b57960ba13/tox-4.58.0-py3-none-any.whl", hash = "sha256:dcae21f5f015f3a67658e35644cce0d1aa0dedcd06f3927f95d84e1717f6cea5", size = 223298, upload-time = "2026-07-21T13:10:34.731Z" }, +] + +[[package]] +name = "tox-uv" +version = "1.36.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tox-uv-bare" }, + { name = "uv" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/d7/3fce976b9e295218a2d7e541e0f1e9b1259cb893de7a8d277952a66a798d/tox_uv-1.36.0-py3-none-any.whl", hash = "sha256:5f81b39be3fe4e14c6b9bb7ba637ed97d34efa6214efd5f525d95ee9559a99ac", size = 6564, upload-time = "2026-07-21T13:09:54.316Z" }, +] + +[[package]] +name = "tox-uv-bare" +version = "1.36.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "tox" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/df/9f90a59de8c87cece6e691eee53dc1cb0a824d73aea8f380ae2f6ecb71de/tox_uv_bare-1.36.0.tar.gz", hash = "sha256:d9b0a2fd0f74fa65d9597108f8a0ef7abb08651c9196a998a6073b781b45cfd0", size = 32548, upload-time = "2026-07-21T13:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/0a/6dc462e4fb543305283a6157c80f43e3d12ca4702da6ae6521d541c6b55c/tox_uv_bare-1.36.0-py3-none-any.whl", hash = "sha256:ba397dd0396df95a75744d4e42a50ee27207c0ffcf277b62ffba9c3de455a939", size = 22489, upload-time = "2026-07-21T13:09:55.389Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "uv" +version = "0.11.31" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/f0/501fe8a234ac96ea8869e84cb47b3bd77e39a0e80ee01950713e24fe1c4a/uv-0.11.31.tar.gz", hash = "sha256:763609d59721af5b8522e16deac6cffe8055f82bb837740c708917506f305185", size = 6045932, upload-time = "2026-07-22T01:48:45.407Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/6a/065e1e7feaf375eee8d1bb05e5276185708149dd48c27a230f320a0fc8bf/uv-0.11.31-py3-none-linux_armv6l.whl", hash = "sha256:6adaaf151f53fef04dec685f0816d304c09a091b2b609746f86ee7c55ada6bcd", size = 25838313, upload-time = "2026-07-22T01:47:21.787Z" }, + { url = "https://files.pythonhosted.org/packages/e1/15/529b573723a36badbda1e13a432c3b21a7554b8ddef3b20a2200037051c2/uv-0.11.31-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:2d84b6dd6b1eaf42fc923203d21a5efd052e1982e4f961eccecc2a6905ffbecd", size = 24795386, upload-time = "2026-07-22T01:47:26.882Z" }, + { url = "https://files.pythonhosted.org/packages/52/be/a809b3fe20c3d37bc667de33f38475c4c94f860979d07049ccddb6d91801/uv-0.11.31-py3-none-macosx_11_0_arm64.whl", hash = "sha256:335f3262c4350c004cf6e3b7061200148d670e579bcee7ba0e31c7535f125018", size = 23410594, upload-time = "2026-07-22T01:47:31.43Z" }, + { url = "https://files.pythonhosted.org/packages/c9/9a/ebaacd8b7713fd755d23623e0e8de78dfd001f6abc818034f2e9058035c7/uv-0.11.31-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:e1cf5803c39221387b2fe8be2b522b0529ac732831a2e52a92330e053539995e", size = 25358933, upload-time = "2026-07-22T01:47:36.544Z" }, + { url = "https://files.pythonhosted.org/packages/81/34/c30568a0f9e556be766c341106bf6ca2ef5c8067be6c11665a53df0549f1/uv-0.11.31-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:68ae6974ffbd04703e138654e83220a16e7b0b679271a8f209f928928dd399f8", size = 25346175, upload-time = "2026-07-22T01:47:41.132Z" }, + { url = "https://files.pythonhosted.org/packages/b5/63/18467b66f578dc121ec6d4af78074a0db06b27627b072fc433226a99a384/uv-0.11.31-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:48f7ec906eaebf9717a01ba0f7635cd0cac648ff5c8fff3a57b8805e6bd49078", size = 25381240, upload-time = "2026-07-22T01:47:45.659Z" }, + { url = "https://files.pythonhosted.org/packages/b8/43/b51d6b8ad1307f51dd75154d623d6a527c6de600086bb0446251047d2e5e/uv-0.11.31-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a2cfd1638420f9a2a7dbca71c808edaf3929b6d8f4ec2ceac2f27014150d0e3", size = 26661822, upload-time = "2026-07-22T01:47:50.42Z" }, + { url = "https://files.pythonhosted.org/packages/30/9f/008c859ea3fc0d25d6ac32e1293a0795c737b0a472a8603b5e511b56659c/uv-0.11.31-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aec65d8f54403e60f32c50e44d98b6420de55211ad22a340927efc5db6ef4205", size = 27594901, upload-time = "2026-07-22T01:47:55.444Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ca/65a2856e79a208f8a1ece0ac077fbee531db7455608c06ab677b2513cbc4/uv-0.11.31-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5610fea306dc6ce5021482d272e6372f0c3dfd1e24ec061f90b1b9287263ac58", size = 26708620, upload-time = "2026-07-22T01:48:00.2Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c3/019ecbf3564d909c55fcf065592aff90b8b386d679e379caf356de4473f9/uv-0.11.31-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44ac79fca5807122676701279a1f36d7917a922f25a0ab5c5cf58a252f666e7e", size = 26894006, upload-time = "2026-07-22T01:48:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/f6/9b/b67aa8736f9f82a9f99cec93c28d66d77ff42126914784a3f680bc737b56/uv-0.11.31-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:c4d4b34264017dc9047d0d49f09363a5e20b388481cddc39d5c44b16b3c2a57c", size = 25504398, upload-time = "2026-07-22T01:48:09.859Z" }, + { url = "https://files.pythonhosted.org/packages/44/d1/37e3a30f55e1c623fca484efbb80b6e157b922ee79f5cb7b1c0ff5005f0f/uv-0.11.31-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:9ce168c7323aee61ef07220c815f1b3e3a1b74241acb9f56c0b7fc4794dad600", size = 26307040, upload-time = "2026-07-22T01:48:14.555Z" }, + { url = "https://files.pythonhosted.org/packages/00/cc/f607ba28a93100c55b3e048838f85481f8b55a24e3a338e42c151f5884ae/uv-0.11.31-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f3f8f58030ba4f711542d581b5fc3cde54db75a773fc873178f7b353f68f8711", size = 26425088, upload-time = "2026-07-22T01:48:19.204Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ae/dd865e1d680799f05ff32895689700a23f37e905aac9807c93521fc76d8c/uv-0.11.31-py3-none-musllinux_1_1_i686.whl", hash = "sha256:b1384887f8a4a0b0dfb8c6c81b2f819d1771015a96c70f89ef12559df8206b28", size = 25920399, upload-time = "2026-07-22T01:48:23.866Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0a/45ebfd783235a7a39ae1e99dc0bf26c083ea24a37584e530c7fbb6e38a21/uv-0.11.31-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:c6e052de498086b2014020536829b7e2b6f173ba95b07e55e9e0f85ac00a3927", size = 27126383, upload-time = "2026-07-22T01:48:28.376Z" }, + { url = "https://files.pythonhosted.org/packages/d9/c7/4cf78823c123efd3bdac50eb26f4b8fc2c222962d47918a7bb2b465b6522/uv-0.11.31-py3-none-win32.whl", hash = "sha256:03e18e463ecf0e1c347f901f9a8739059d07e2e2ebce72c0f8f1b9328a349c6f", size = 24644301, upload-time = "2026-07-22T01:48:33.094Z" }, + { url = "https://files.pythonhosted.org/packages/e1/4f/f2c3d0993ebab255a2dd7c476678c0307da03d890fb98761e8221d7bb043/uv-0.11.31-py3-none-win_amd64.whl", hash = "sha256:1a4bb0030d9070a4831a4f3115c5489998da7ca936e569a72696c90af469177a", size = 27699662, upload-time = "2026-07-22T01:48:37.708Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8b/259e12b510c655f743f9a0e3171e6e9276dfd35a058d04d6aeef1fc4a897/uv-0.11.31-py3-none-win_arm64.whl", hash = "sha256:88ab5fdbeff4ab10ac890ab2dd01b7ad62b92251665423e4f68b1cf977fbe635", size = 25849721, upload-time = "2026-07-22T01:48:42.513Z" }, +] + +[[package]] +name = "virtualenv" +version = "21.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "python-discovery" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/25/e367a7229b0914772ca8d81b41fde012d9feda68523b52644a571bb21ce8/virtualenv-21.7.0.tar.gz", hash = "sha256:7f9519b9432ff11b6e1a3e94061664efc2ff99ea21780e3cf4f6bd0a5da8b37c", size = 5527510, upload-time = "2026-07-21T13:12:14.109Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/7a/ae29312b1e88a22e81f5d21fc11526d2a114089776c2550d2b205b6c2a47/virtualenv-21.7.0-py3-none-any.whl", hash = "sha256:a8370c1c5530fbabf955e40b8fbbc68a431648b10f9433faa587db30a06e51dd", size = 5507078, upload-time = "2026-07-21T13:12:12.136Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] From fbaaa532ac3109825675981dd3b7d9da69e75f1d Mon Sep 17 00:00:00 2001 From: Allan Stockman Rugano Date: Wed, 22 Jul 2026 18:28:50 +0200 Subject: [PATCH 2/3] Updated documentation and sandbox --- .coverage | Bin 69632 -> 69632 bytes CHANGELOG.md | 8 +- README.md | 18 +++- docs/sandbox.md | 103 +++++++++++++++++++++++ examples/sandbox_e2e.py | 135 +++++++++++++++++++++++++++++ mkdocs.yml | 1 + pyproject.toml | 2 + src/paydunya/dmp.py | 46 +++++++--- src/paydunya/invoice.py | 12 +-- src/paydunya/models.py | 75 ++++++----------- tests/test_compat.py | 55 +++++++++--- tests/test_dmp.py | 12 ++- tests/test_invoice.py | 2 +- uv.lock | 182 +++++++++++++++++++++++++++++++++++++++- 14 files changed, 559 insertions(+), 92 deletions(-) create mode 100644 docs/sandbox.md create mode 100644 examples/sandbox_e2e.py diff --git a/.coverage b/.coverage index 3ec550a2b777a796d657e97404599515ef962845..1550b7963c7d218159eacee95fe76fbda9838357 100644 GIT binary patch literal 69632 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 literal 69632 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 G+5ZoN^@eEx diff --git a/CHANGELOG.md b/CHANGELOG.md index b7c0ce2..eb6eb02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,12 @@ in PayDunya's current documentation. Use the JavaScript-based PSR flow (documented at https://developers.paydunya.com/doc/EN/psr_plugins/api_psr) where your server creates a checkout invoice and returns the token +- **Pydantic v2** — all models (`Store`, `InvoiceItem`, `Customer`, `Tax`, + `Actions`) are now Pydantic `BaseModel` classes with built-in validation + (email format via `EmailStr`, amount bounds, positive quantity, required + fields). Invalid input raises `ValidationError` at the SDK boundary instead + of being sent to the API. - Python 3.10+ only (dropped all Python 2 and Python < 3.10 support) -- `SimpleJSON` fallback removed - `httpx` replaces `requests` ### Added @@ -22,6 +26,8 @@ payment page fields - **Docs-compliant items format** — items now keyed as `item_0`, `item_1`, ... matching the official HTTP/JSON documentation +- **Sandbox E2E example** — `examples/sandbox_e2e.py` with interactive + payment confirmation polling - Type hints throughout, `py.typed` marker - Pytest-based test suite with httpx mocking (no network required) - MkDocs Material documentation in `docs/` diff --git a/README.md b/README.md index e07e063..7990ca6 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Python client library for integrating [PayDunya](https://paydunya.com) payment s - **PER** — Payment And Redistribution (DirectPay): transfer funds to other PayDunya accounts - **DMP** — Payment Request API: send payment links to customers via SMS or Email - **IPN** — Instant Payment Notification hash verification helper +- Pydantic v2 models with built-in validation (email format, amount bounds, required fields) - Fully typed, `httpx`-based transport, Python 3.10+ ## Installation @@ -114,10 +115,18 @@ if verify_ipn_hash( master_key="your-master-key", received_hash=request.POST["data"]["hash"], ): - # data genuinely comes from PayDunya status = request.POST["data"]["status"] ``` +## Sandbox Testing + +PayDunya provides fictitious customer accounts to test without real money. See the [Sandbox Testing guide in the docs](https://github.com/paydunyadev/paydunya-python-master/blob/main/docs/sandbox.md) or run the interactive example: + +```bash +PAYDUNYA_MASTER_KEY="..." PAYDUNYA_PRIVATE_KEY="..." PAYDUNYA_TOKEN="..." \\ + python examples/sandbox_e2e.py +``` + ## API Keys Register at [paydunya.com/integration-setups](https://paydunya.com/integration-setups), create an application, and retrieve your three keys: @@ -134,9 +143,10 @@ The v2.0 API has been redesigned: - `PaydunyaClient(master_key, private_key, token, mode="test")` replaces the old `paydunya.debug` / `paydunya.api_keys` globals - `OPR` has been removed — use the PSR JavaScript flow documented at [developers.paydunya.com](https://developers.paydunya.com/doc/EN/psr_plugins/api_psr) -- `Invoice.confirm(token)` is now a clear method (not auto-using `self._response`) -- Items are now keyed `item_0`, `item_1` (docs-compliant, formerly a flat array started from `item_1`) -- `Invoice.customer` pre-fill is now supported via `set_customer()` +- `Invoice.confirm(token)` is now a clear method +- Items are now keyed `item_0`, `item_1` (docs-compliant, formerly a flat array) +- Pydantic v2 models replace plain dataclasses — input validation (email format, amount bounds, required fields) happens at the SDK boundary +- `Invoice.customer` pre-fill via `set_customer()` ## Development diff --git a/docs/sandbox.md b/docs/sandbox.md new file mode 100644 index 0000000..db07e65 --- /dev/null +++ b/docs/sandbox.md @@ -0,0 +1,103 @@ +# Sandbox Testing + +PayDunya provides a complete sandbox environment where you can test every +payment flow without real money, cards, or mobile money accounts. + +## Fictitious Customers + +The sandbox uses **fictitious customer accounts** (comptes fictifs) to +simulate payments. Each fictitious customer has a name, email, phone number, +and a **virtual balance**. When a payment is made in the sandbox, PayDunya +debits the fictitious balance — no real funds move. + +### Creating a fictitious customer + +1. Log in to your [PayDunya account](https://paydunya.com/login) +2. Go to **Integration API** in the left menu +3. Click the **[Fictitious customers](https://paydunya.com/integration-setups/sandbox-accounts)** tab +4. Fill in the name, email address, and initial balance +5. Click **Create** + +You can create multiple fictitious customers and **reload their balance +manually at any time** from the same tab. + +## Making a Test Payment + +1. Create a checkout invoice with your **test API keys** and `mode="test"`: + + ```python + from paydunya import Invoice, InvoiceItem, PaydunyaClient, Store + + client = PaydunyaClient( + master_key="your-master-key", + private_key="test_private_...", + token="your-token", + mode="test", + ) + + store = Store(name="Test Shop") + invoice = Invoice(client, store) + invoice.set_total_amount(5000) + invoice.set_description("Sandbox test") + + response = invoice.create() + print(response["response_text"]) # sandbox payment page URL + ``` + +2. Open the URL in your browser. You'll see the sandbox payment page. + +3. Choose any payment method (card, Orange Money, Wave, etc.) — they all + work in the sandbox without real accounts. + +4. Enter your **fictitious customer's email or phone number** when prompted. + +5. Complete the payment. Your fictitious balance is debited. + +## Debugging Your Requests + +PayDunya provides a debugging tool called **Fictitious Internal Data**: + +1. Go to **Integration API** → **[Fictitious internal data](https://paydunya.com/integration-setups/sandbox-data)** +2. You'll see a list of all test transactions transmitted to the server +3. Click **details** next to any entry to see the exact JSON payload your + code sent, plus the full server response + +This is extremely useful when debugging payload shapes or checking whether +optional fields (customer, channels, custom_data) are correctly transmitted. + +## Automated End-to-End Script + +The SDK includes an interactive sandbox E2E script at +[`examples/sandbox_e2e.py`](https://github.com/paydunyadev/paydunya-python-master/blob/main/examples/sandbox_e2e.py). + +### Running it + +```bash +export PAYDUNYA_MASTER_KEY="your-test-master-key" +export PAYDUNYA_PRIVATE_KEY="test_private_..." +export PAYDUNYA_TOKEN="your-test-token" + +python examples/sandbox_e2e.py +``` + +The script: +1. Creates a checkout invoice in test mode +2. Prints the sandbox payment URL and instructions +3. Polls every 5 seconds (up to 3 minutes) until the payment is completed +4. Displays the confirmation result (status, customer info, receipt URL) + +## CI / Automated Testing + +For continuous integration and automated tests, use **`pytest-httpx`** to +mock all HTTP calls — no network access, no API keys required. The SDK's +own test suite (43+ tests) runs entirely offline this way. See the +`tests/` directory for examples of mock-based test patterns. + +## Transitioning to Production + +When you're ready: +1. Update your application to **Enable production mode** in the dashboard +2. Replace test API keys with your production keys +3. Set `mode="live"` in `PaydunyaClient` +4. Perform one or two small real transactions to verify everything works +5. Remove any hardcoded keys from your source code — use environment variables diff --git a/examples/sandbox_e2e.py b/examples/sandbox_e2e.py new file mode 100644 index 0000000..660573e --- /dev/null +++ b/examples/sandbox_e2e.py @@ -0,0 +1,135 @@ +"""End-to-end sandbox test for PayDunya PAR API. + +Usage: + Set your test API keys as environment variables, then run: + + PAYDUNYA_MASTER_KEY="..." \\ + PAYDUNYA_PRIVATE_KEY="test_private_..." \\ + PAYDUNYA_TOKEN="..." \\ + python examples/sandbox_e2e.py + +The script creates a checkout invoice in test mode, prints the sandbox +payment page URL, and polls for the payment status until the +fictitious-customer payment is completed. +""" + +from __future__ import annotations + +import os +import sys +import time + +from paydunya import Invoice +from paydunya import InvoiceItem +from paydunya import PaydunyaClient +from paydunya import Store + + +def main() -> None: + master_key = os.environ.get("PAYDUNYA_MASTER_KEY") + private_key = os.environ.get("PAYDUNYA_PRIVATE_KEY") + token = os.environ.get("PAYDUNYA_TOKEN") + + if not all((master_key, private_key, token)): + print("Missing API keys. Set PAYDUNYA_MASTER_KEY, PAYDUNYA_PRIVATE_KEY, " + "PAYDUNYA_TOKEN environment variables.") + sys.exit(1) + + client = PaydunyaClient( + master_key=master_key, + private_key=private_key, + token=token, + mode="test", + ) + + store = Store(name="Sandbox E2E Shop", tagline="End-to-end test store") + items = [ + InvoiceItem( + name="Test Product", + quantity=1, + unit_price="5000", + total_price="5000", + description="A sample product for sandbox testing", + ), + ] + + invoice = Invoice(client, store) + invoice.add_items(items) + invoice.set_total_amount(5000) + invoice.set_description("Sandbox E2E test invoice") + invoice.set_return_url("https://example.com/thanks") + invoice.set_cancel_url("https://example.com/cancelled") + + print("Creating sandbox invoice...") + response = invoice.create() + payment_url = response.get("response_text", "") + invoice_token = response.get("token", "") + + if not payment_url: + print(f"Unexpected response from create: {response}") + sys.exit(1) + + print(f"\n{'=' * 60}") + print(" INVOICE CREATED") + print(f"{'=' * 60}") + print(f" Token: {invoice_token}") + print(f" Payment URL: {payment_url}") + print(f"{'=' * 60}") + + print(""" +=== SANDBOX PAYMENT INSTRUCTIONS === + +1. Open the Payment URL above in your browser. +2. On the PayDunya sandbox payment page, pay using your fictitious + customer account credentials (email or phone number). +3. If you haven't created a fictitious customer yet: + - Go to https://paydunya.com/integration-setups + - Click the "Fictitious customers" tab + - Create one with an email, phone, and a sufficient balance. +4. After payment, return to this terminal — the script will detect + the completed payment automatically. +""") + + print("Waiting for payment (polling every 5 seconds, 3 min timeout)...") + deadline = time.monotonic() + 180 + last_status = "" + + while time.monotonic() < deadline: + try: + result = invoice.confirm(invoice_token) + except Exception as exc: + print(f" Confirm error: {exc}") + time.sleep(5) + continue + + status = result.get("status", "unknown") + if status != last_status: + print(f" Status: {status}") + last_status = status + + if status == "completed": + print(f"\n{'=' * 60}") + print(" PAYMENT CONFIRMED") + print(f"{'=' * 60}") + print(f" Status: {status}") + print(f" Token: {invoice_token}") + if "customer" in result: + c = result["customer"] + print(f" Customer: {c.get('name', '')} <{c.get('email', '')}>") + if "receipt_url" in result: + print(f" Receipt: {result['receipt_url']}") + print(f"{'=' * 60}") + return + + if status in ("cancelled", "failed"): + print(f"\nPayment {status}. Run again to retry.") + sys.exit(1) + + time.sleep(5) + + print("\nTimed out waiting for payment (3 minutes). The invoice may have expired.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/mkdocs.yml b/mkdocs.yml index dfd7a00..343cb34 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -20,6 +20,7 @@ nav: - PER / DirectPay: per.md - DMP (Payment Request API): dmp.md - IPN Verification: ipn.md + - Sandbox Testing: sandbox.md plugins: - search diff --git a/pyproject.toml b/pyproject.toml index 823940f..f94f29c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,8 @@ classifiers = [ ] dependencies = [ "httpx>=0.27", + "pydantic>=2", + "email-validator>=2", ] [project.urls] diff --git a/src/paydunya/dmp.py b/src/paydunya/dmp.py index 7d4dda0..a673e1f 100644 --- a/src/paydunya/dmp.py +++ b/src/paydunya/dmp.py @@ -1,7 +1,25 @@ from __future__ import annotations +from pydantic import BaseModel +from pydantic import EmailStr +from pydantic import Field +from pydantic import model_validator + from paydunya.client import PaydunyaClient -from paydunya.exceptions import APIError + + +class _DMPRequest(BaseModel): + amount: float | int = Field(ge=200, le=3_000_000) + recipient_email: EmailStr | None = None + recipient_phone: str | None = None + support_fees: bool = False + send_notification: bool = True + + @model_validator(mode="after") + def _check_recipient(self) -> _DMPRequest: + if not self.recipient_email and not self.recipient_phone: + raise ValueError("recipient_email or recipient_phone is required") + return self class DMP: @@ -17,21 +35,23 @@ def create( support_fees: bool = False, send_notification: bool = True, ) -> dict: - if amount < 200 or amount > 3_000_000: - raise APIError("4000", "amount must be between 200 and 3,000,000") - - if not recipient_email and not recipient_phone: - raise APIError("4000", "recipient_email or recipient_phone is required") + req = _DMPRequest( + amount=amount, + recipient_email=recipient_email, + recipient_phone=recipient_phone, + support_fees=support_fees, + send_notification=send_notification, + ) payload: dict = { - "amount": amount, - "support_fees": 1 if support_fees else 0, - "send_notification": 1 if send_notification else 0, + "amount": req.amount, + "support_fees": 1 if req.support_fees else 0, + "send_notification": 1 if req.send_notification else 0, } - if recipient_email: - payload["recipient_email"] = recipient_email - if recipient_phone: - payload["recipient_phone"] = recipient_phone + if req.recipient_email: + payload["recipient_email"] = req.recipient_email + if req.recipient_phone: + payload["recipient_phone"] = req.recipient_phone return self._client.dmp_post("dmp-api", payload) diff --git a/src/paydunya/invoice.py b/src/paydunya/invoice.py index 6d5a8b8..359df09 100644 --- a/src/paydunya/invoice.py +++ b/src/paydunya/invoice.py @@ -45,7 +45,7 @@ def set_callback_url(self, url: str) -> None: self.actions.callback_url = url def set_customer(self, name: str = "", email: str = "", phone: str = "") -> None: - self.customer = Customer(name=name, email=email, phone=phone) + self.customer = Customer(name=name or None, email=email or None, phone=phone or None) def add_item(self, item: InvoiceItem) -> None: self.items.append(item) @@ -73,11 +73,11 @@ def _build_payload(self) -> dict[str, Any]: items_dict: dict[str, Any] = {} for idx, item in enumerate(self.items): - items_dict[f"item_{idx}"] = item.asdict() + items_dict[f"item_{idx}"] = item.model_dump(exclude_none=True) taxes_dict: dict[str, Any] = {} for idx, tax in enumerate(self.taxes): - taxes_dict[f"tax_{idx}"] = tax.asdict() + taxes_dict[f"tax_{idx}"] = tax.model_dump(exclude_none=True) invoice_data: dict[str, Any] = { "total_amount": total, @@ -91,19 +91,19 @@ def _build_payload(self) -> dict[str, Any]: if self.channels: invoice_data["channels"] = self.channels - customer_data = self.customer.asdict() + customer_data = self.customer.model_dump(exclude_none=True) if customer_data: invoice_data["customer"] = customer_data payload: dict[str, Any] = { "invoice": invoice_data, - "store": self.store.asdict(), + "store": self.store.model_dump(exclude_none=True), } if self.custom_data: payload["custom_data"] = self.custom_data - actions_data = self.actions.asdict() + actions_data = self.actions.model_dump(exclude_none=True) if actions_data: payload["actions"] = actions_data diff --git a/src/paydunya/models.py b/src/paydunya/models.py index f9128b4..edadfa4 100644 --- a/src/paydunya/models.py +++ b/src/paydunya/models.py @@ -1,64 +1,39 @@ from __future__ import annotations -from dataclasses import dataclass -from typing import Any +from pydantic import BaseModel +from pydantic import EmailStr +from pydantic import Field -@dataclass -class Customer: - name: str = "" - email: str = "" - phone: str = "" +class Customer(BaseModel): + name: str | None = None + email: EmailStr | None = None + phone: str | None = None - def asdict(self) -> dict[str, str]: - return {k: v for k, v in self.__dict__.items() if v} +class Store(BaseModel): + name: str = Field(min_length=1) + tagline: str | None = None + postal_address: str | None = None + phone_number: str | None = None + website_url: str | None = None + logo_url: str | None = None -@dataclass -class Store: - name: str - tagline: str = "" - postal_address: str = "" - phone_number: str = "" - website_url: str = "" - logo_url: str = "" - def asdict(self) -> dict[str, str]: - return {k: v for k, v in self.__dict__.items() if v} - - -@dataclass -class InvoiceItem: - name: str - quantity: int +class InvoiceItem(BaseModel): + name: str = Field(min_length=1) + quantity: int = Field(gt=0) unit_price: str total_price: str - description: str = "" - - def asdict(self) -> dict[str, str]: - return { - "name": self.name, - "quantity": str(self.quantity), - "unit_price": self.unit_price, - "total_price": self.total_price, - "description": self.description, - } - - -@dataclass -class Actions: - cancel_url: str = "" - return_url: str = "" - callback_url: str = "" + description: str | None = None - def asdict(self) -> dict[str, str]: - return {k: v for k, v in self.__dict__.items() if v} +class Tax(BaseModel): + name: str = Field(min_length=1) + amount: float | int = Field(ge=0) -@dataclass -class Tax: - name: str - amount: float | int - def asdict(self) -> dict[str, Any]: - return {"name": self.name, "amount": self.amount} +class Actions(BaseModel): + cancel_url: str | None = None + return_url: str | None = None + callback_url: str | None = None diff --git a/tests/test_compat.py b/tests/test_compat.py index 0db0e54..3d37b59 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -2,10 +2,16 @@ import json +import pytest +from pydantic import ValidationError + from paydunya import Invoice from paydunya import InvoiceItem from paydunya import Store from paydunya.client import TEST_BASE +from paydunya.models import Actions +from paydunya.models import Customer +from paydunya.models import Tax def test_invoice_with_module_level_api(client_test, mock_http): @@ -85,25 +91,48 @@ def test_store_asdict_in_payload(client_test, mock_http): assert payload["store"]["phone_number"] == "336530583" -def test_model_dataclasses(): - from paydunya.models import Actions - from paydunya.models import Customer - from paydunya.models import InvoiceItem - from paydunya.models import Store - from paydunya.models import Tax - +def test_model_dump(): item = InvoiceItem(name="X", quantity=1, unit_price="10", total_price="10") - assert item.asdict()["quantity"] == "1" + assert item.model_dump(exclude_none=True)["quantity"] == 1 customer = Customer(name="John") - assert customer.asdict()["name"] == "John" - assert "email" not in customer.asdict() + assert customer.model_dump(exclude_none=True)["name"] == "John" + assert "email" not in customer.model_dump(exclude_none=True) store = Store(name="Shop") - assert store.asdict() == {"name": "Shop"} + assert store.model_dump(exclude_none=True) == {"name": "Shop"} tax = Tax(name="VAT", amount=18) - assert tax.asdict()["amount"] == 18 + assert tax.model_dump(exclude_none=True)["amount"] == 18 actions = Actions() - assert actions.asdict() == {} + assert actions.model_dump(exclude_none=True) == {} + + +class TestModelValidation: + def test_store_name_required(self): + with pytest.raises(ValidationError): + Store(name="") + + def test_invoice_item_quantity_positive(self): + with pytest.raises(ValidationError): + InvoiceItem(name="X", quantity=0, unit_price="10", total_price="10") + + def test_invoice_item_negative_quantity(self): + with pytest.raises(ValidationError): + InvoiceItem(name="X", quantity=-1, unit_price="10", total_price="10") + + def test_customer_invalid_email(self): + with pytest.raises(ValidationError): + Customer(email="not-an-email") + + def test_tax_negative_amount(self): + with pytest.raises(ValidationError): + Tax(name="VAT", amount=-1) + + def test_store_empty_optional_fields_excluded(self): + store = Store(name="Shop") + dumped = store.model_dump(exclude_none=True) + assert dumped == {"name": "Shop"} + assert "tagline" not in dumped + assert "website_url" not in dumped diff --git a/tests/test_dmp.py b/tests/test_dmp.py index b01a18a..bf9aa51 100644 --- a/tests/test_dmp.py +++ b/tests/test_dmp.py @@ -3,6 +3,7 @@ import json import pytest +from pydantic import ValidationError from paydunya.client import DMP_BASE from paydunya.dmp import DMP @@ -105,19 +106,24 @@ def test_create_no_notification(self, client_test, mock_http): def test_amount_below_minimum(self, client_test): dmp = DMP(client_test) - with pytest.raises(APIError, match="between 200"): + with pytest.raises(ValidationError, match="greater than or equal to 200"): dmp.create(amount=50, recipient_email="a@b.com") def test_amount_above_maximum(self, client_test): dmp = DMP(client_test) - with pytest.raises(APIError, match="between 200"): + with pytest.raises(ValidationError, match="less than or equal to"): dmp.create(amount=5_000_000, recipient_email="a@b.com") def test_no_recipient(self, client_test): dmp = DMP(client_test) - with pytest.raises(APIError, match="recipient"): + with pytest.raises(ValidationError, match="recipient"): dmp.create(amount=500) + def test_invalid_email(self, client_test): + dmp = DMP(client_test) + with pytest.raises(ValidationError, match="email"): + dmp.create(amount=500, recipient_email="not-an-email") + def test_check_status(self, client_test, mock_http): mock_http.add_response( method="POST", diff --git a/tests/test_invoice.py b/tests/test_invoice.py index 46ddbe6..54eea51 100644 --- a/tests/test_invoice.py +++ b/tests/test_invoice.py @@ -37,7 +37,7 @@ def test_items_are_keyed_as_item_0(self, client_test, mock_http): assert "item_0" in payload["invoice"]["items"] assert payload["invoice"]["items"]["item_0"]["name"] == "Product A" - assert payload["invoice"]["items"]["item_0"]["quantity"] == "2" + assert payload["invoice"]["items"]["item_0"]["quantity"] == 2 def test_multiple_items_sequential_keys(self, client_test, mock_http): store = Store(name="Test Shop") diff --git a/uv.lock b/uv.lock index ce26710..2a6232a 100644 --- a/uv.lock +++ b/uv.lock @@ -2,6 +2,15 @@ version = 1 revision = 3 requires-python = ">=3.10" +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + [[package]] name = "anyio" version = "4.14.2" @@ -285,6 +294,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" }, ] +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "email-validator" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, +] + [[package]] name = "exceptiongroup" version = "1.3.1" @@ -667,7 +698,9 @@ name = "paydunya" version = "2.0.0" source = { editable = "." } dependencies = [ + { name = "email-validator" }, { name = "httpx" }, + { name = "pydantic" }, ] [package.dev-dependencies] @@ -688,7 +721,11 @@ docs = [ ] [package.metadata] -requires-dist = [{ name = "httpx", specifier = ">=0.27" }] +requires-dist = [ + { name = "email-validator", specifier = ">=2" }, + { name = "httpx", specifier = ">=0.27" }, + { name = "pydantic", specifier = ">=2" }, +] [package.metadata.requires-dev] dev = [ @@ -741,6 +778,137 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/49/bc925106abcdac498074f2cbe6137e94e09f418dd2b7775df5b577dc0313/pre_commit-4.6.1-py2.py3-none-any.whl", hash = "sha256:0e3b2942510d1fb34eec167a3ec57331bf8442122f1153a9fb8b58f5c49b2717", size = 226186, upload-time = "2026-07-21T20:56:57.064Z" }, ] +[[package]] +name = "pydantic" +version = "2.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/08/f1ba952f1c8ae5581c70fa9c6da89f247b83e3dd8c09c035d5d7931fc23d/pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4", size = 2113146, upload-time = "2026-05-06T13:37:36.537Z" }, + { url = "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5", size = 1949769, upload-time = "2026-05-06T13:37:46.365Z" }, + { url = "https://files.pythonhosted.org/packages/64/ba/bfb1d928fd5b49e1258935ff104ae356e9fd89384a55bf9f847e9193ad40/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba", size = 1974958, upload-time = "2026-05-06T13:37:28.611Z" }, + { url = "https://files.pythonhosted.org/packages/4e/74/76223bfb117b64af743c9b6670d1364516f5c0604f96b48f3272f6af6cc6/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b", size = 2042118, upload-time = "2026-05-06T13:36:55.216Z" }, + { url = "https://files.pythonhosted.org/packages/cb/7b/848732968bc8f48f3187542f08358b9d842db564147b256669426ebb1652/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c", size = 2222876, upload-time = "2026-05-06T13:38:25.455Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2f/e90b63ee2e14bd8d3db8f705a6d75d64e6ee1b7c2c8833747ce706e1e0ce/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50", size = 2286703, upload-time = "2026-05-06T13:37:53.304Z" }, + { url = "https://files.pythonhosted.org/packages/ba/1e/acc4d70f88a0a277e4a1fa77ebb985ceabaf900430f875bf9338e11c9420/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd", size = 2092042, upload-time = "2026-05-06T13:38:46.981Z" }, + { url = "https://files.pythonhosted.org/packages/a9/da/0a422b57bf8504102bf3c4ccea9c41bab5a5cee6a54650acf8faf67f5a24/pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01", size = 2117231, upload-time = "2026-05-06T13:39:23.146Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2a/2ac13c3af305843e23c5078c53d135656b3f05a2fd78cb7bbbb12e97b473/pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d", size = 2168388, upload-time = "2026-05-06T13:40:08.06Z" }, + { url = "https://files.pythonhosted.org/packages/72/04/2beacf7e1607e93eefe4aed1b4709f079b905fb77530179d4f7c71745f22/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4", size = 2184769, upload-time = "2026-05-06T13:38:13.901Z" }, + { url = "https://files.pythonhosted.org/packages/9e/29/d2b9fd9f539133548eaf622c06a4ce176cb46ac59f32d0359c4abc0de047/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f", size = 2319312, upload-time = "2026-05-06T13:39:08.24Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/0f7a5b85fec6075bea96e3ef9187de38fccced0de92c1e7feda8d5cc7bb9/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39", size = 2361817, upload-time = "2026-05-06T13:38:43.2Z" }, + { url = "https://files.pythonhosted.org/packages/25/a4/73363fec545fd3ec025490bdda2743c56d0dd5b6266b1a53bbe9e4265375/pydantic_core-2.46.4-cp310-cp310-win32.whl", hash = "sha256:2f84c03c8607173d16b5a854ec68a2f9079ae03237a54fb506d13af47e1d018d", size = 1987085, upload-time = "2026-05-06T13:39:25.497Z" }, + { url = "https://files.pythonhosted.org/packages/01/aa/62f082da2c91fac1c234bc9ee0066257ce83f0604abd72e4c9d5991f2d84/pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf", size = 2074311, upload-time = "2026-05-06T13:39:59.922Z" }, + { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" }, + { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" }, + { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" }, + { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" }, + { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" }, + { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" }, + { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" }, + { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" }, + { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" }, + { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" }, + { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" }, + { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" }, + { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, + { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, + { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, + { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, + { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, + { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, + { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, + { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, + { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, + { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, + { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, + { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, + { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, + { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, + { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, + { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, + { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, + { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, + { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, + { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, + { url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" }, + { url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" }, + { url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" }, + { url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" }, + { url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" }, + { url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" }, + { url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" }, + { url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" }, + { url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" }, + { url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" }, + { url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" }, + { url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" }, + { url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" }, + { url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" }, + { url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" }, + { url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" }, + { url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" }, + { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" }, + { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" }, + { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" }, + { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" }, + { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" }, + { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, + { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, + { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" }, + { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" }, + { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" }, + { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" }, +] + [[package]] name = "pygments" version = "2.20.0" @@ -1092,6 +1260,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, ] +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + [[package]] name = "urllib3" version = "2.7.0" From 39325640d116b86a52cccff9c3dbd3f1ddc64cbb Mon Sep 17 00:00:00 2001 From: Allan Stockman Rugano Date: Thu, 23 Jul 2026 11:25:56 +0200 Subject: [PATCH 3/3] Updated links --- .github/workflows/ci.yml | 4 ++-- .github/workflows/docs.yml | 39 ++++++++++++++++++++++++++++++++++++++ .gitignore | 33 +++++++++++++++++++++++--------- README.md | 5 +++-- docs/sandbox.md | 2 +- mkdocs.yml | 3 ++- pyproject.toml | 4 ++-- 7 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9453653..8a043de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [main, master] + branches: [develop, master] pull_request: - branches: [main, master] + branches: [develop, master] jobs: lint: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..70bfd0d --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,39 @@ +name: Docs + +on: + push: + branches: [develop, master] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + - run: uv sync --no-dev --group docs + - run: uv run mkdocs build --strict + - uses: actions/upload-pages-artifact@v3 + with: + path: site/ + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index d38f39c..a112fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,36 @@ -# Compiled python modules. +# Python +__pycache__/ *.pyc +*.pyo -# Setuptools distribution folder. +# Virtual environments +.venv/ + +# Setuptools distribution /dist/ /build/ - -# Python egg metadata, regenerated from source files by setuptools. /*.egg-info - -# ignore MANIFEST as it is auto-generated by distutils MANIFEST -# .tox +# tox .tox/ -# emacs buffers +# MkDocs build output +/site/ + +# Testing +.pytest_cache/ +.coverage +.coverage.* +htmlcov/ + +# Linting +.ruff_cache/ + +# Dev tooling +.env + +# Emacs *~ */#* .#* -/test.py diff --git a/README.md b/README.md index 7990ca6..2f72515 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # PayDunya Python SDK -[![CI](https://github.com/paydunyadev/paydunya-python-master/actions/workflows/ci.yml/badge.svg)](https://github.com/paydunyadev/paydunya-python-master/actions/workflows/ci.yml) +[![CI](https://github.com/srugano/paydunya-python-api/actions/workflows/ci.yml/badge.svg)](https://github.com/srugano/paydunya-python-api/actions/workflows/ci.yml) +[![Docs](https://github.com/srugano/paydunya-python-api/actions/workflows/docs.yml/badge.svg)](https://srugano.github.io/paydunya-python-api/) [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://pypi.org/project/paydunya/) [![PyPI](https://img.shields.io/pypi/v/paydunya.svg)](https://pypi.org/project/paydunya/) @@ -120,7 +121,7 @@ if verify_ipn_hash( ## Sandbox Testing -PayDunya provides fictitious customer accounts to test without real money. See the [Sandbox Testing guide in the docs](https://github.com/paydunyadev/paydunya-python-master/blob/main/docs/sandbox.md) or run the interactive example: +PayDunya provides fictitious customer accounts to test without real money. See the [Sandbox Testing guide in the docs](https://github.com/srugano/paydunya-python-api/blob/develop/docs/sandbox.md) or run the interactive example: ```bash PAYDUNYA_MASTER_KEY="..." PAYDUNYA_PRIVATE_KEY="..." PAYDUNYA_TOKEN="..." \\ diff --git a/docs/sandbox.md b/docs/sandbox.md index db07e65..88ebb76 100644 --- a/docs/sandbox.md +++ b/docs/sandbox.md @@ -68,7 +68,7 @@ optional fields (customer, channels, custom_data) are correctly transmitted. ## Automated End-to-End Script The SDK includes an interactive sandbox E2E script at -[`examples/sandbox_e2e.py`](https://github.com/paydunyadev/paydunya-python-master/blob/main/examples/sandbox_e2e.py). +[`examples/sandbox_e2e.py`](https://github.com/srugano/paydunya-python-api/blob/develop/examples/sandbox_e2e.py). ### Running it diff --git a/mkdocs.yml b/mkdocs.yml index 343cb34..762b117 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,6 +1,7 @@ site_name: PayDunya Python SDK site_description: Python client for PayDunya payment services (PAR, PSR, PER, DMP) -repo_url: https://github.com/paydunyadev/paydunya-python-master +site_url: https://srugano.github.io/paydunya-python-api/ +repo_url: https://github.com/srugano/paydunya-python-api theme: name: material palette: diff --git a/pyproject.toml b/pyproject.toml index f94f29c..9887edc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,8 +31,8 @@ dependencies = [ [project.urls] Homepage = "https://developers.paydunya.com/" Documentation = "https://developers.paydunya.com/doc/EN/introduction" -Repository = "https://github.com/paydunyadev/paydunya-python-master" -Issues = "https://github.com/paydunyadev/paydunya-python-master/issues" +Repository = "https://github.com/srugano/paydunya-python-api" +Issues = "https://github.com/srugano/paydunya-python-api/issues" [dependency-groups] dev = [