diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 26e06af..1321828 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ # Default owners for the classic Python SDK -* @johnxing-amigo @caly-yang-amigo +* @johnxing-amigo @caly-amigo diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0bccd67..b4f49cf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,6 @@ on: description: "Version increment type (patch|minor|major)" required: true type: string - default: "patch" dry_run: description: "Dry run (skip upload)" required: false @@ -57,11 +56,13 @@ jobs: uses: ./.github/workflows/test.yml with: skip_codecov: true - secrets: inherit release: runs-on: blacksmith-4vcpu-ubuntu-2404 needs: test + env: + VERSION_TYPE: ${{ inputs.version_type }} + DRY_RUN: ${{ inputs.dry_run }} steps: - name: Create GitHub App token (release-bot) @@ -85,8 +86,9 @@ jobs: - name: Fetch OpenAPI spec if: ${{ inputs.regenerate_models }} id: fetch_spec + env: + SPEC_URL: ${{ inputs.spec_url }} run: | - SPEC_URL="${{ inputs.spec_url }}" if [ -z "$SPEC_URL" ]; then SPEC_URL="https://api.amigo.ai/v1/openapi.json" fi @@ -94,7 +96,7 @@ jobs: curl -fSL -o specs/openapi-new.json "$SPEC_URL" cp specs/openapi-new.json specs/openapi-baseline.json - # Generator always fetches remote; no local spec path needed + # Generation uses the committed snapshot, or the explicit refresh above. - name: Setup Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 @@ -127,11 +129,22 @@ jobs: python -m scripts.gen_models echo "โœ… Models generated successfully" + - name: Validate regenerated package + if: ${{ inputs.regenerate_models }} + run: | + ruff check . + mypy src/amigo_sdk/ --ignore-missing-imports + pytest + - name: Increment version id: new_version run: | - echo "๐Ÿ”„ Incrementing ${{ inputs.version_type }} version..." - hatch version ${{ inputs.version_type }} + case "$VERSION_TYPE" in + patch|minor|major) ;; + *) echo "::error::Unsupported version type"; exit 1 ;; + esac + echo "๐Ÿ”„ Incrementing $VERSION_TYPE version..." + hatch version "$VERSION_TYPE" NEW_VERSION=$(hatch version) echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT echo "โœ… Version updated: ${{ steps.current_version.outputs.version }} โ†’ $NEW_VERSION" @@ -208,6 +221,7 @@ jobs: REPO: ${{ github.repository }} NEW_VERSION: ${{ steps.new_version.outputs.version }} PREV_VERSION: ${{ steps.current_version.outputs.version }} + RELEASE_COMMITS: ${{ steps.release_commits.outputs.markdown }} run: | PREV_TAG="v${PREV_VERSION}" NEW_TAG="v${NEW_VERSION}" @@ -219,7 +233,7 @@ jobs: { echo "## What's Changed in ${NEW_TAG}" echo "" - echo "${{ steps.release_commits.outputs.markdown }}" + printf '%s\n' "$RELEASE_COMMITS" echo "" echo "---" echo "" @@ -285,20 +299,22 @@ jobs: retention-days: 30 - name: Release Summary + env: + RELEASE_COMMITS: ${{ steps.release_commits.outputs.markdown }} run: | echo "## ๐ŸŽ‰ Release Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "- **Version**: ${{ steps.new_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY echo "- **Previous**: ${{ steps.current_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **Type**: ${{ inputs.version_type }} release" >> $GITHUB_STEP_SUMMARY + echo "- **Type**: $VERSION_TYPE release" >> $GITHUB_STEP_SUMMARY echo "- **Target**: PyPI" >> $GITHUB_STEP_SUMMARY - echo "- **Dry Run**: ${{ inputs.dry_run }}" >> $GITHUB_STEP_SUMMARY + echo "- **Dry Run**: $DRY_RUN" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### ๐Ÿงพ New Commits" >> $GITHUB_STEP_SUMMARY - printf '%s\n' "${{ steps.release_commits.outputs.markdown }}" >> $GITHUB_STEP_SUMMARY + printf '%s\n' "$RELEASE_COMMITS" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - if [ "${{ inputs.dry_run }}" = "false" ]; then + if [ "$DRY_RUN" = "false" ]; then echo "### ๐Ÿ“ฆ Package Links" >> $GITHUB_STEP_SUMMARY echo "- [PyPI Package](https://pypi.org/project/amigo_sdk/${{ steps.new_version.outputs.version }}/)" >> $GITHUB_STEP_SUMMARY echo "- [GitHub Release](https://github.com/${{ github.repository }}/releases/tag/v${{ steps.new_version.outputs.version }})" >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore index 82515e4..f2a9bfa 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,9 @@ coverage.xml # CI/Temp OpenAPI spec (fetched during workflows) specs/openapi-new.json + +# Compiled Python artifacts +*.py[cod] + +# Generated MkDocs site +/site/ diff --git a/CLAUDE.md b/CLAUDE.md index c6012f7..c6a2ac3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,7 +11,7 @@ Amigo AI Python SDK (`amigo_sdk`) -- a Python client library for the Amigo AI AP - **Format:** `ruff format src/ tests/` (check only: `ruff format --check src/ tests/`) - **Generate models from OpenAPI:** `python scripts/gen_models.py` - **Build:** `hatch build` (outputs sdist and wheel to `dist/`) -- **Type check:** `mypy src/amigo_sdk/` (mypy in dev deps, CI step runs with continue-on-error) +- **Type check:** `mypy src/amigo_sdk/` (mypy in dev deps; required CI check) ## Architecture @@ -90,6 +90,6 @@ Tests for resources use shared helpers in `tests/resources/helpers.py`: GitHub Actions workflow (`.github/workflows/test.yml`) runs on Python 3.11, 3.12, 3.13: 1. `ruff check .` 2. `ruff format --check .` -3. `mypy src/amigo_sdk/` (continue-on-error) +3. `mypy src/amigo_sdk/ --ignore-missing-imports` (required) 4. `pytest --cov=src` 5. Integration tests run separately (non-blocking, require secrets) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bc80d19..6bc1d81 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,15 +14,15 @@ pip install -e ".[dev]" ### Validation -- `check` runs formatting, linting, and tests -- `check --fix` auto-fixes what it can, then reruns checks -- `check --fast` runs the fast path without tests +- `python scripts/check.py` runs formatting, linting, and tests +- `python scripts/check.py --fix` auto-fixes what it can, then reruns checks +- `python scripts/check.py --fast` runs the fast path without tests ### Codegen And Docs -- `gen-models` regenerates models from the committed `specs/openapi-baseline.json` snapshot -- `sync-openapi` refreshes `specs/openapi-baseline.json` from the live classic API before regeneration -- `mkdocs build --strict` builds the docs site +- `python scripts/gen_models.py` regenerates models from the committed `specs/openapi-baseline.json` snapshot +- `python scripts/sync_openapi.py` refreshes `specs/openapi-baseline.json` from the live classic API before regeneration +- Install docs dependencies with `pip install -e ".[docs]"`, then `mkdocs build --strict` builds the docs site ## Testing @@ -34,7 +34,7 @@ python -m pytest -m integration python -m pytest --cov=src ``` -Integration tests require valid Amigo API credentials in the environment. +Integration tests require valid Amigo API credentials in the environment. Unit tests use mocked requests. Run `mypy src/amigo_sdk/ --ignore-missing-imports` as well; it is a required CI check. Development scripts run from this checkout and are not commands installed by the public wheel. ## Project Structure @@ -57,9 +57,9 @@ examples/ Before opening a PR: -1. Run `check --fix` +1. Run `python scripts/check.py --fix` 2. Run `python -m pytest` -3. Run `sync-openapi` and `gen-models` if the API contract changed +3. Run `python scripts/sync_openapi.py` and `python scripts/gen_models.py` if the API contract changed 4. Update README or docs if customer-visible behavior changed ## Release Notes diff --git a/README.md b/README.md index 15d27e2..ed24513 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The Platform API is where new workspace-scoped capabilities land first, but the | If you need | Start here | | --- | --- | | Existing org-scoped integrations on `api.amigo.ai` from Python | `amigo_sdk` | -| New workspace-scoped integrations on `api.platform.amigo.ai` | [Platform API docs](https://docs.amigo.ai/api-reference) today. A first-party Python migration path will follow as platform-native coverage expands | +| New workspace-scoped integrations on `api.platform.amigo.ai` | [Platform API docs](https://docs.amigo.ai/api-reference) today. Use direct HTTP for Platform integrations from Python; this package remains Classic-only | ## Documentation @@ -66,6 +66,10 @@ Python `3.11+` is required. pip install amigo_sdk ``` +Before making requests, obtain Classic organization credentials and a user authorized to read the target resources. Keep API keys in server-side environment variables or a secret manager. The examples below read conversation data; they require access to an existing organization. + +For the 2.0.0 generated-model changes, review the [current SDK upgrade guidance](https://docs.amigo.ai/api-reference/change-logs/sdk-ecosystem#september-2026-compatibility-releases) and recheck the package registry when choosing a version. + ## Quick Start ### Sync Client @@ -142,11 +146,11 @@ from amigo_sdk.models import ( ) ``` -Public builds are generated from the committed [`specs/openapi-baseline.json`](./specs/openapi-baseline.json) snapshot in this repo so generated models stay deterministic across machines and CI runs. Refresh that snapshot before regenerating models: +Public builds are generated from the committed [`specs/openapi-baseline.json`](./specs/openapi-baseline.json) snapshot in this repo so generated models stay deterministic across machines and CI runs. From a source checkout with development dependencies installed, refresh that snapshot before regenerating models: ```bash -sync-openapi -gen-models +python scripts/sync_openapi.py +python scripts/gen_models.py ``` ## Error Handling diff --git a/pyproject.toml b/pyproject.toml index e249449..1a7c89d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ dynamic = ["version"] dependencies = [ "httpx>=0.25,<1.0", "pydantic>=2.7,<3.0", - "pydantic-settings>=2.0,<3.0", + "pydantic-settings>=2.14.2,<3.0", "email-validator>=2.0,<3.0", ] @@ -34,21 +34,16 @@ Repository = "https://github.com/amigo-ai/amigo-python-sdk" Issues = "https://github.com/amigo-ai/amigo-python-sdk/issues" Changelog = "https://github.com/amigo-ai/amigo-python-sdk/blob/main/CHANGELOG.md" -[project.scripts] -gen-models = "scripts.gen_models:main" -check = "scripts.check:main" -sync-openapi = "scripts.sync_openapi:main" - [project.optional-dependencies] dev = [ - "pytest>=7.0,<9.0", - "pytest-asyncio>=0.21,<1.0", + "pytest>=9.0.3,<10.0", + "pytest-asyncio>=1.0,<2.0", "pytest-cov>=4.0,<6.0", "pytest-httpx>=0.30,<1.0", - "python-dotenv>=1.0,<2.0", + "python-dotenv>=1.2.2,<2.0", "ruff>=0.1,<1.0", "mypy>=1.0", - "datamodel-code-generator[http]>=0.21,<1.0", + "datamodel-code-generator[http]>=0.64,<1.0", ] docs = [ "mkdocs>=1.6", diff --git a/scripts/__init__.pyc b/scripts/__init__.pyc deleted file mode 100644 index 08fcf3e..0000000 Binary files a/scripts/__init__.pyc and /dev/null differ diff --git a/scripts/gen_models.py b/scripts/gen_models.py index ca743a5..ed94eac 100644 --- a/scripts/gen_models.py +++ b/scripts/gen_models.py @@ -134,6 +134,7 @@ def main() -> None: use_operation_id_as_name=True, reuse_model=True, set_default_enum_member=True, + disable_timestamp=True, aliases=aliases, collapse_root_models=False, ) diff --git a/src/amigo_sdk/generated/model.py b/src/amigo_sdk/generated/model.py index 3295760..e1e7786 100644 --- a/src/amigo_sdk/generated/model.py +++ b/src/amigo_sdk/generated/model.py @@ -1,6 +1,5 @@ # generated by datamodel-codegen: # filename: -# timestamp: 2026-09-08T01:00:51+00:00 from __future__ import annotations diff --git a/uv.lock b/uv.lock index e39769a..3cf0a82 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,10 @@ version = 1 revision = 3 requires-python = ">=3.11" +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version < '3.14'", +] [[package]] name = "amigo-sdk" @@ -31,7 +35,7 @@ docs = [ [package.metadata] requires-dist = [ - { name = "datamodel-code-generator", extras = ["http"], marker = "extra == 'dev'", specifier = ">=0.21,<1.0" }, + { name = "datamodel-code-generator", extras = ["http"], marker = "extra == 'dev'", specifier = ">=0.64,<1.0" }, { name = "email-validator", specifier = ">=2.0,<3.0" }, { name = "httpx", specifier = ">=0.25,<1.0" }, { name = "mkdocs", marker = "extra == 'docs'", specifier = ">=1.6" }, @@ -39,12 +43,12 @@ requires-dist = [ { name = "mkdocstrings", extras = ["python"], marker = "extra == 'docs'", specifier = ">=0.27" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.0" }, { name = "pydantic", specifier = ">=2.7,<3.0" }, - { name = "pydantic-settings", specifier = ">=2.0,<3.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0,<9.0" }, - { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.21,<1.0" }, + { name = "pydantic-settings", specifier = ">=2.14.2,<3.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=9.0.3,<10.0" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=1.0,<2.0" }, { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.0,<6.0" }, { name = "pytest-httpx", marker = "extra == 'dev'", specifier = ">=0.30,<1.0" }, - { name = "python-dotenv", marker = "extra == 'dev'", specifier = ">=1.0,<2.0" }, + { name = "python-dotenv", marker = "extra == 'dev'", specifier = ">=1.2.2,<2.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1,<1.0" }, ] provides-extras = ["dev", "docs"] @@ -224,14 +228,11 @@ wheels = [ [[package]] name = "click" -version = "8.3.1" +version = "8.5.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz", hash = "sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34", size = 382235, upload-time = "2026-08-26T13:33:14.56Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, + { url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", hash = "sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", size = 125251, upload-time = "2026-08-26T13:33:12.928Z" }, ] [[package]] @@ -337,23 +338,21 @@ toml = [ [[package]] name = "datamodel-code-generator" -version = "0.52.2" +version = "0.76.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argcomplete" }, - { name = "black" }, + { name = "black", marker = "sys_platform != 'emscripten'" }, { name = "genson" }, { name = "inflect" }, - { name = "isort" }, + { name = "isort", marker = "sys_platform != 'emscripten'" }, { name = "jinja2" }, - { name = "packaging" }, { name = "pydantic" }, { name = "pyyaml" }, - { name = "tomli", marker = "python_full_version < '3.12'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/8f/7594b293c5da78c7b7685facfc07b96d03af9f833f5f5742a028b6a1d564/datamodel_code_generator-0.52.2.tar.gz", hash = "sha256:54b25789980deafed50c455c25a5d391c177a9f74f0e14b0edeb6db69f1185a9", size = 789610, upload-time = "2026-01-05T17:25:50.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/cd/97b5ce0bc7452199a06204e1252fe10ad63cc37c76c2e9f76146b766b708/datamodel_code_generator-0.76.2.tar.gz", hash = "sha256:c8c25e24b5b90c1c45fc40309fedd0a2f571425c7b6efae97efb317c03325c32", size = 2260230, upload-time = "2026-09-04T11:37:47.931Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/8d/72a75327e05a26d5fb7fa511a7d78af18198dc2595bbb179da0c9e4b6fbc/datamodel_code_generator-0.52.2-py3-none-any.whl", hash = "sha256:3ee19ec38190b76bb4119aa67ddce25b3447dd4e5c6bfd47b03a9937c50f5aac", size = 249759, upload-time = "2026-01-05T17:25:48.845Z" }, + { url = "https://files.pythonhosted.org/packages/b3/7a/00b736585a6fac1e9c94275a07d8e470a3accdaab37b54d13fdc1c985bc0/datamodel_code_generator-0.76.2-py3-none-any.whl", hash = "sha256:8cc2bffa5a7e81a4b5a1cfce28530eaf9be465f3591bb7cb53030eb0c956f6d9", size = 661183, upload-time = "2026-09-04T11:37:45.73Z" }, ] [package.optional-dependencies] @@ -452,11 +451,11 @@ wheels = [ [[package]] name = "idna" -version = "3.11" +version = "3.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/f7/abb373e5757eaec4b922b92f97ec8d6d7e057cf06778247604fbc4e7c3f3/idna-3.19.tar.gz", hash = "sha256:5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15", size = 215237, upload-time = "2026-08-18T05:14:24.27Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl", hash = "sha256:815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4", size = 68550, upload-time = "2026-08-18T05:14:22.343Z" }, ] [[package]] @@ -721,7 +720,7 @@ wheels = [ [[package]] name = "mkdocs-material" -version = "9.7.5" +version = "9.7.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "babel" }, @@ -736,9 +735,9 @@ dependencies = [ { name = "pymdown-extensions" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/76/5c202fecdc45d53e83e03a85bae70c48b6c81e9f87f0bc19a9e9c723bdc0/mkdocs_material-9.7.5.tar.gz", hash = "sha256:f76bdab532bad1d9c57ca7187b37eccf64dd12e1586909307f8856db3be384ea", size = 4097749, upload-time = "2026-03-10T15:43:22.809Z" } +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/45/e1/e8080dcfa95cca267662a6f4afe29237452bdeb5a2a6555ac83646d21915/mkdocs_material-9.7.5-py3-none-any.whl", hash = "sha256:7cf9df2ff121fd098ff6e05c732b0be3699afca9642e2dfe4926c40eb5873eec", size = 9305251, upload-time = "2026-03-10T15:43:19.089Z" }, + { 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]] @@ -1013,43 +1012,43 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.12.0" +version = "2.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } +sdist = { url = "https://files.pythonhosted.org/packages/68/ca/31c57507b13119d7d3cfa1576dad2911a4861e3be07b579395f4e9d393f9/pydantic_settings-2.15.0.tar.gz", hash = "sha256:694b793e84f766ba76a90ebdefc01d0a9a045dab0382bee70393da93712ad117", size = 261253, upload-time = "2026-08-07T09:24:57.419Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, + { url = "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl", hash = "sha256:0ba092c291c94baceb5eff768aa0d56400a457585bc0175925a5a5510303da42", size = 69413, upload-time = "2026-08-07T09:24:55.839Z" }, ] [[package]] name = "pygments" -version = "2.19.2" +version = "2.21.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, ] [[package]] name = "pymdown-extensions" -version = "10.21" +version = "11.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/63/06673d1eb6d8f83c0ea1f677d770e12565fb516928b4109c9e2055656a9e/pymdown_extensions-10.21.tar.gz", hash = "sha256:39f4a020f40773f6b2ff31d2cd2546c2c04d0a6498c31d9c688d2be07e1767d5", size = 853363, upload-time = "2026-02-15T20:44:06.748Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/17/2db4b414de89659144488e0d9c6c0bf0c8395841dc12d81d0532cc6ef310/pymdown_extensions-11.0.2.tar.gz", hash = "sha256:9506fcbe66fa355a775b768084334238dd6805020ac4b92bea0c0dda6f8f223d", size = 855419, upload-time = "2026-08-22T19:28:47.236Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/2c/5b079febdc65e1c3fb2729bf958d18b45be7113828528e8a0b5850dd819a/pymdown_extensions-10.21-py3-none-any.whl", hash = "sha256:91b879f9f864d49794c2d9534372b10150e6141096c3908a455e45ca72ad9d3f", size = 268877, upload-time = "2026-02-15T20:44:05.464Z" }, + { url = "https://files.pythonhosted.org/packages/a6/43/9f45ec4d14e596efc32c925a78104934790438b0c0628b70d741016734ad/pymdown_extensions-11.0.2-py3-none-any.whl", hash = "sha256:259910762019732caa1dfd76f3faa62c59f191d46573e80bcb1d13c0f675bbe5", size = 269929, upload-time = "2026-08-22T19:28:45.389Z" }, ] [[package]] name = "pytest" -version = "8.4.2" +version = "9.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1058,21 +1057,22 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +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/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, + { 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-asyncio" -version = "0.26.0" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8e/c4/453c52c659521066969523e87d85d54139bbd17b78f09532fb8eb8cdb58e/pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f", size = 54156, upload-time = "2025-03-25T06:22:28.883Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/7f/338843f449ace853647ace35870874f69a764d251872ed1b4de9f234822c/pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0", size = 19694, upload-time = "2025-03-25T06:22:27.807Z" }, + { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" }, ] [[package]] @@ -1090,15 +1090,15 @@ wheels = [ [[package]] name = "pytest-httpx" -version = "0.35.0" +version = "0.36.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1f/89/5b12b7b29e3d0af3a4b9c071ee92fa25a9017453731a38f08ba01c280f4c/pytest_httpx-0.35.0.tar.gz", hash = "sha256:d619ad5d2e67734abfbb224c3d9025d64795d4b8711116b1a13f72a251ae511f", size = 54146, upload-time = "2024-11-28T19:16:54.237Z" } +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/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl", hash = "sha256:ee11a00ffcea94a5cbff47af2114d34c5b231c326902458deed73f9c459fd744", size = 19442, upload-time = "2024-11-28T19:16:52.787Z" }, + { 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]] @@ -1115,11 +1115,11 @@ wheels = [ [[package]] name = "python-dotenv" -version = "1.2.1" +version = "1.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/53/ed9d74092561d4b01a2ef1349d52cdbc135e526c245f366b089cfca6de49/python_dotenv-1.2.3.tar.gz", hash = "sha256:a20a594dabeaa385725aa239d5244871c143ecb356add8a20fcf23773a6c3a35", size = 58945, upload-time = "2026-08-16T16:54:54.067Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl", hash = "sha256:904552145e8bfed22162c09dab1c2b9b54fefa7b23ba780f4f26ca0316b0f0d9", size = 22780, upload-time = "2026-08-16T16:54:52.473Z" }, ] [[package]] @@ -1225,7 +1225,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.5" +version = "2.34.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -1233,9 +1233,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +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/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, + { 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]] @@ -1362,11 +1362,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.6.3" +version = "2.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +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/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, + { 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]]