From 1503fb52b8f62295351bb6fd396afc6d3ef8f4e7 Mon Sep 17 00:00:00 2001 From: marcuswood-oai <323319819+marcuswood-oai@users.noreply.github.com> Date: Wed, 28 Oct 2026 13:13:38 -0700 Subject: [PATCH] chore: migrate development type checking to ty --- .castiron.stats.yml | 6 +- .devcontainer/devcontainer.json | 4 +- .github/workflows/ci.yml | 34 +- CONTRIBUTING.md | 49 +-- examples/audio.py | 2 +- examples/browser-use-demo/booking.py | 3 +- examples/browser-use-demo/exercise.py | 4 +- examples/computer-desktop/guest/install.py | 4 +- examples/computer-desktop/guest/setup.py | 10 +- .../guest/test_action_admission.py | 4 +- .../computer-desktop/guest/test_receipt.py | 2 +- examples/demo.py | 2 + examples/image_stream.py | 2 +- examples/realtime/audio_util.py | 2 - examples/realtime/push_to_talk_app.py | 14 +- examples/realtime/test_push_to_talk_app.py | 9 +- examples/responses/websocket.py | 2 +- examples/video.py | 3 +- pyproject.toml | 137 +++----- scripts/bootstrap | 2 - scripts/bootstrap-node | 2 +- scripts/castiron/generated-files.json | 90 +++--- scripts/check-python-version-policy.py | 6 +- scripts/detect-breaking-changes | 6 +- scripts/fixtures/computer_use_smoke.py | 3 +- scripts/lint | 3 +- scripts/pyrightconfig.breaking-changes.json | 21 +- scripts/pyrightconfig.browser-demo.json | 12 - scripts/pyrightconfig.browser-example.json | 11 - scripts/pyrightconfig.computer-example.json | 12 - scripts/run-pyright | 4 +- scripts/test | 2 +- scripts/utils/node-tooling.cjs | 2 +- src/openai/__init__.py | 89 +++--- src/openai/_base_client.py | 56 ++-- src/openai/_client.py | 260 +++++++-------- src/openai/_compat.py | 27 +- src/openai/_exceptions.py | 14 +- src/openai/_extras/numpy_proxy.py | 2 +- src/openai/_extras/sounddevice_proxy.py | 4 +- src/openai/_files.py | 2 +- src/openai/_legacy_response.py | 38 +-- src/openai/_models.py | 72 ++--- src/openai/_provider.py | 6 +- src/openai/_response.py | 56 ++-- src/openai/_utils/_compat.py | 4 +- src/openai/_utils/_datetime_parse.py | 3 +- src/openai/_utils/_proxy.py | 6 +- src/openai/_utils/_transform.py | 12 +- src/openai/_utils/_typing.py | 12 +- src/openai/_utils/_utils.py | 12 +- src/openai/auth/_workload.py | 2 +- src/openai/helpers/local_audio_player.py | 1 - src/openai/helpers/microphone.py | 4 +- src/openai/lib/_assistants_runs.py | 20 +- src/openai/lib/_assistants_threads.py | 8 +- src/openai/lib/_bedrock_auth.py | 10 +- src/openai/lib/_chat_completion_resources.py | 4 +- src/openai/lib/_client_auth.py | 6 +- src/openai/lib/_module_runtime.py | 3 +- src/openai/lib/_parsing/_audio.py | 8 +- src/openai/lib/_parsing/_completions.py | 4 +- src/openai/lib/_parsing/_embeddings.py | 4 +- src/openai/lib/_parsing/_responses.py | 4 +- src/openai/lib/_response_resources.py | 6 +- src/openai/lib/_vector_stores.py | 8 +- src/openai/lib/bedrock.py | 2 +- src/openai/lib/beta/agents/_output.py | 2 +- src/openai/lib/beta/agents/_schema.py | 6 +- src/openai/lib/beta/agents/_tools.py | 10 +- src/openai/lib/browser.py | 16 +- src/openai/lib/computer.py | 3 +- src/openai/lib/responses_tool_runner.py | 6 +- src/openai/lib/streaming/_assistants.py | 9 +- src/openai/lib/streaming/chat/_completions.py | 47 ++- src/openai/lib/streaming/responses/_events.py | 2 +- src/openai/providers/vertex.py | 4 +- src/openai/resources/audio/transcriptions.py | 2 +- src/openai/resources/audio/translations.py | 26 +- src/openai/resources/beta/assistants.py | 120 +++---- src/openai/resources/beta/threads/messages.py | 120 +++---- .../resources/beta/threads/runs/runs.py | 144 +++------ .../resources/beta/threads/runs/steps.py | 48 +-- src/openai/resources/beta/threads/threads.py | 120 +++---- src/openai/resources/files.py | 24 +- .../fine_tuning/checkpoints/permissions.py | 24 +- src/openai/resources/images.py | 24 +- src/openai/resources/videos.py | 260 ++++++--------- .../beta_response_custom_tool_call_item.py | 2 +- ...a_response_custom_tool_call_output_item.py | 2 +- .../beta_response_function_tool_call_item.py | 4 +- .../types/chat/parsed_chat_completion.py | 5 +- .../types/chat/parsed_function_tool_call.py | 1 - .../evals/runs/output_item_list_response.py | 2 +- .../runs/output_item_retrieve_response.py | 2 +- src/openai/types/responses/parsed_response.py | 5 +- .../response_custom_tool_call_item.py | 2 +- .../response_custom_tool_call_output_item.py | 2 +- .../response_function_tool_call_item.py | 4 +- tests/api_resources/audio/test_speech.py | 2 - .../audio/test_transcriptions.py | 6 +- .../api_resources/audio/test_translations.py | 2 - .../beta/agents/sessions/test_artifacts.py | 2 - .../beta/agents/sessions/test_events.py | 6 +- .../beta/agents/test_sessions.py | 6 +- tests/api_resources/beta/test_assistants.py | 2 - tests/api_resources/beta/test_realtime.py | 2 - tests/api_resources/beta/test_responses.py | 10 +- tests/api_resources/beta/test_threads.py | 8 +- .../beta/threads/runs/test_steps.py | 2 - .../beta/threads/test_messages.py | 2 - tests/api_resources/beta/threads/test_runs.py | 12 +- tests/api_resources/chat/test_completions.py | 6 +- .../containers/files/test_content.py | 2 - .../checkpoints/test_permissions.py | 2 - tests/api_resources/live/test_sessions.py | 2 - tests/api_resources/realtime/test_calls.py | 2 - tests/api_resources/skills/test_content.py | 2 - .../skills/versions/test_content.py | 2 - tests/api_resources/test_completions.py | 6 +- tests/api_resources/test_files.py | 2 - tests/api_resources/test_images.py | 12 +- tests/api_resources/test_responses.py | 10 +- tests/api_resources/test_videos.py | 6 +- tests/conftest.py | 2 +- tests/lib/bedrock_live.py | 7 +- tests/lib/beta/agents/test_tools.py | 24 +- tests/lib/chat/test_completions.py | 2 +- tests/lib/chat/test_completions_streaming.py | 8 +- tests/lib/live/test_websocket_roles.py | 8 +- .../lib/responses/test_compaction_progress.py | 2 +- tests/lib/responses/test_error_diagnostics.py | 4 +- .../responses/test_lifecycle_replacements.py | 6 +- tests/lib/responses/test_null_output_items.py | 12 +- .../responses/test_websocket_accumulator.py | 2 +- tests/lib/snapshots.py | 2 +- .../streaming/agents/test_creation_tools.py | 3 + tests/lib/streaming/agents/test_output.py | 6 +- tests/lib/streaming/agents/test_streams.py | 2 +- tests/lib/test_assistant_tool_call_deltas.py | 4 +- tests/lib/test_assistants.py | 10 +- tests/lib/test_azure.py | 12 +- tests/lib/test_bedrock.py | 15 +- tests/lib/test_bedrock_provider.py | 2 +- tests/lib/test_bedrock_runtime.py | 2 +- tests/lib/test_browser.py | 6 +- tests/lib/test_browser_registration.py | 6 +- tests/lib/test_computer.py | 5 +- tests/lib/test_decisions_tool_runner.py | 15 +- tests/lib/test_old_api.py | 4 +- tests/lib/test_realtime_websocket_contract.py | 8 +- tests/lib/test_responses_tool_runner.py | 9 +- tests/lib/test_runner_server_tools.py | 11 +- tests/lib/test_vertex_provider.py | 3 +- tests/lib/test_video_polling.py | 3 - tests/test_client.py | 62 ++-- tests/test_files.py | 5 +- tests/test_httpx2.py | 8 +- tests/test_image_safety_identifier.py | 2 +- tests/test_lazy_imports.py | 2 +- tests/test_models.py | 38 +-- tests/test_module_client.py | 3 +- tests/test_required_args.py | 2 +- tests/test_transform.py | 44 ++- tests/test_union_parsing.py | 2 +- tests/test_utils/test_assert_matches_type.py | 12 + tests/test_utils/test_datetime_parse.py | 4 +- tests/test_utils/test_json.py | 2 +- tests/test_utils/test_typing.py | 16 +- tests/test_uv_workflows.py | 30 +- tests/test_websocket_connection_options.py | 22 +- .../test_x509_workload_identity_hardening.py | 3 +- tests/utils.py | 22 +- uv.lock | 299 ++---------------- 174 files changed, 1308 insertions(+), 1877 deletions(-) delete mode 100644 scripts/pyrightconfig.browser-demo.json delete mode 100644 scripts/pyrightconfig.browser-example.json delete mode 100644 scripts/pyrightconfig.computer-example.json create mode 100644 tests/test_utils/test_assert_matches_type.py diff --git a/.castiron.stats.yml b/.castiron.stats.yml index 058f52d7e9..ad96f5a66a 100644 --- a/.castiron.stats.yml +++ b/.castiron.stats.yml @@ -1,7 +1,7 @@ schema_version: 1 -generation_id: c181b60a-9c3f-4fab-adb0-ec99e1b9164b +generation_id: 5f43d20e-1fa7-4356-a5cf-9ba76ebd71ce openapi_spec_hash: d86a987b0943f67209611629cfe2926f openapi_transformed_spec_hash: f98b6939664e5171dadad31a12ecf50a config_hash: 0e042fd083471fc089bcbfe7011a7d01 -codegen_sha: e7d3eec72178efe4bd1c41d2923c5636e5f41500 -codegen_hash: 5808ff69b455e321be73db3a9c2640505dddd64b0418583f71301147baa3171d +codegen_sha: eaa28252a89f885820afa16bbd1a753ec589a3c1 +codegen_hash: e1d1fbd9e1e10bd7f346d72af1f6a726fbf8c6f7ef655552bfc339f2be788c90 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 88fcd37453..b5ff6e94d7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,13 +12,13 @@ "customizations": { "vscode": { "extensions": [ - "ms-python.python" + "ms-python.python", + "astral-sh.ty" ], "settings": { "terminal.integrated.shell.linux": "/bin/bash", "python.pythonPath": ".venv/bin/python", "python.defaultInterpreterPath": ".venv/bin/python", - "python.typeChecking": "basic", "terminal.integrated.env.linux": { "PATH": "/home/vscode/.local/bin:${env:PATH}" } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76fc0cb8c4..29af514ec4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,8 +77,6 @@ jobs: with: persist-credentials: false - - uses: ./.github/actions/setup-node-tooling - - name: Set up uv uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: @@ -160,8 +158,6 @@ jobs: - name: Use this job's Playwright installation run: printf 'PLAYWRIGHT_BROWSERS_PATH=%s/openai-python-playwright\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" - - uses: ./.github/actions/setup-node-tooling - - name: Set up uv uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: @@ -170,11 +166,9 @@ jobs: enable-cache: true - name: Check the optional Playwright demo - env: - PYRIGHT_PROJECT: scripts/pyrightconfig.browser-demo.json run: >- - uv run --locked --all-extras --group browser-demo python -c - 'import os, sys; os.execv("./scripts/run-pyright", ["./scripts/run-pyright", "--pythonpath", sys.executable])' + uv run --locked --all-extras --group browser-demo + ty check --extra-search-path examples/browser examples/browser-use-demo - name: Install Chromium for local demo security checks run: uv run --locked --all-extras --group browser-demo playwright install --with-deps chromium @@ -195,7 +189,11 @@ jobs: strategy: fail-fast: false matrix: - provider: [browser, computer] + include: + - provider: browser + directory: examples/browser + - provider: computer + directory: examples/computer-desktop steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: @@ -204,8 +202,6 @@ jobs: - name: Use this job's Playwright installation run: printf 'PLAYWRIGHT_BROWSERS_PATH=%s/openai-python-playwright\n' "$RUNNER_TEMP" >> "$GITHUB_ENV" - - uses: ./.github/actions/setup-node-tooling - - name: Set up uv uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 with: @@ -214,13 +210,9 @@ jobs: enable-cache: true - name: Check optional provider types against this checkout - env: - PYRIGHT_PROJECT: scripts/pyrightconfig.${{ matrix.provider }}-example.json run: >- - uv run --locked --all-extras --no-default-groups --group dev --group provider-${{ matrix.provider }} python -c - 'import os, pathlib, sys; import openai; - assert pathlib.Path(openai.__file__).resolve() == pathlib.Path("src/openai/__init__.py").resolve(), "Provider check replaced this OpenAI checkout"; - os.execv("./scripts/run-pyright", ["./scripts/run-pyright", "--pythonpath", sys.executable])' + uv run --locked --all-extras --no-default-groups --group dev --group provider-${{ matrix.provider }} + ty check ${{ matrix.directory }} - name: Install Chromium for local browser security checks if: matrix.provider == 'browser' @@ -253,7 +245,10 @@ jobs: with: persist-credentials: false - - uses: ./.github/actions/setup-node-tooling + - name: Set up Node for the mock-server tooling + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version-file: .node-version - name: Set up Python ${{ matrix.python-version }} id: setup-python @@ -271,6 +266,9 @@ jobs: - name: Bootstrap run: ./scripts/bootstrap + - name: Install the pinned mock-server tooling + run: ./scripts/steady/install + - name: Check concurrent Steady publication run: node scripts/steady/publication.test.cjs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6408e3de16..c57c45adc1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,31 +27,34 @@ must include a release note naming the final compatible SDK release. ### With uv We use [uv](https://docs.astral.sh/uv/) to manage Python, dependencies, and builds. -Install uv 0.12.1 or newer, Node.js at the version in `.node-version`, and -the exact pnpm version in `package.json` (`npm install --global pnpm@11.19.0`). -The Node toolchain is for repository development only, not SDK users or builds. -Then run: +Install uv 0.12.1 or newer. To run the runtime tests, also install Node.js at +the version in `.node-version` for the mock-server tooling. Then run: ```sh $ ./scripts/bootstrap ``` -This installs all SDK extras and Python development tools from `uv.lock`, plus -the contributor tools from `pnpm-lock.yaml`. Bootstrap requires an already -installed Node.js and pnpm; it does not download or switch those tools for you. -Run a -command with `uv run --locked --all-extras`, or activate `.venv` in your shell. +This installs all SDK extras and Python development tools from `uv.lock`. +Run a command with `uv run --locked --all-extras`, or activate `.venv` in your shell. Use `uv lock` after changing dependencies, and commit the updated `uv.lock`. It is the authoritative lockfile; `uv export` can produce a requirements file for tools that need one. -For Node tooling updates, edit `package.json`, run -`pnpm install --lockfile-only --ignore-scripts`, review the dependency and -integrity changes, and commit `pnpm-lock.yaml`. Normal bootstrap uses a frozen -lockfile. pnpm rejects releases that have not cleared the eight-day cooldown, -including packages whose registry metadata omits their publication date. -Pyright runs the local Microsoft package and never invokes npm or -downloads a runtime. Do not use `npx`, `pnpm dlx`, or Corepack auto-downloads. +The separate breaking-change CI job checks previous-version callers with Pyright. +To run that compatibility gate locally, install Node.js at the version in +`.node-version` and the exact pnpm version in `package.json`, then run +`./scripts/bootstrap-node`. Pyright and pnpm are not required for normal bootstrap or lint. Runtime tests +still require Node.js for the Steady mock-server tooling. Before running them, install +the pinned mock server and runtime: + +```sh +$ ./scripts/steady/install +``` + +Node tooling uses the frozen `pnpm-lock.yaml`, an eight-day release cooldown, +and disabled lifecycle scripts. Update it with `pnpm install --lockfile-only +--ignore-scripts` and review the integrity changes. Do not use `npx`, `pnpm dlx`, +or Corepack auto-downloads to run compatibility checks. The default environment uses Pydantic v2. `./scripts/test` also runs the Pydantic-v1 suite in a separate, locked environment. To run that lane alone, @@ -59,7 +62,7 @@ use `./scripts/test-pydantic-v1`. ### Dependency update policy -Routine Python, Node-tooling, and GitHub Actions updates have an eight-day cooldown. uv also +Routine Python, compatibility-checker, and GitHub Actions updates have an eight-day cooldown. uv also excludes Python distribution artifacts uploaded within the last eight days. Dependabot security updates remain enabled and are exempt from Dependabot's version-update cooldown. @@ -209,9 +212,9 @@ installation, integrity checks, and mock-server lifecycle. Most tests require you to [set up a mock server](https://github.com/openai-oss-forks/steady) against the OpenAPI spec to run the tests. -`./scripts/bootstrap` installs the pinned Steady source and Deno runtime. `./scripts/test` starts it automatically when no mock server is running. +`./scripts/steady/install` installs the pinned Steady source and Deno runtime. `./scripts/test` starts it automatically when no mock server is running. Neither `./scripts/test` nor `./scripts/mock` downloads mock tooling. If the local -tool is missing, rerun bootstrap. `TEST_API_BASE_URL` and an already-running +tool is missing, rerun `./scripts/steady/install`. `TEST_API_BASE_URL` and an already-running mock server remain supported. To start the server yourself: ```sh @@ -224,7 +227,13 @@ $ ./scripts/test ## Linting and formatting -This repository uses [Ruff](https://github.com/astral-sh/ruff) to lint and format Python code. +This repository uses [Ruff](https://github.com/astral-sh/ruff) to lint and format Python code, +and [ty](https://docs.astral.sh/ty/) to typecheck it. These are development tools; +installing the SDK does not install a typechecker or require consumers to switch checkers. +Consumers use their own checker and configuration. Keep public annotations, overloads, +exports, and `py.typed` compatible across checkers; repository-only checker settings +are not part of that contract. Preserve compatibility with both supported Pydantic +major versions and the Python versions covered by CI. To lint: diff --git a/examples/audio.py b/examples/audio.py index 880d3b897d..4478faa2fb 100755 --- a/examples/audio.py +++ b/examples/audio.py @@ -29,7 +29,7 @@ def main() -> None: # Legacy translation endpoint: shuts down February 26, 2027. # New integrations should use Realtime translations instead: # https://developers.openai.com/api/docs/deprecations - translation = openai.audio.translations.create( # pyright: ignore[reportDeprecated] + translation = openai.audio.translations.create( # ty: ignore[deprecated] model="whisper-1", file=speech_file_path, ) diff --git a/examples/browser-use-demo/booking.py b/examples/browser-use-demo/booking.py index 49ef166161..f06ece928b 100644 --- a/examples/browser-use-demo/booking.py +++ b/examples/browser-use-demo/booking.py @@ -99,8 +99,9 @@ async def read_page(self, args: ReadPageInput, *, cancelled: Callable[[], bool] await handle.dispose() continue ref = secrets.token_hex(12) + item: BrowserReadElement if role == "textbox": - item: BrowserReadElement = { + item = { "ref": ref, "role": "textbox", "label": label, diff --git a/examples/browser-use-demo/exercise.py b/examples/browser-use-demo/exercise.py index 71cca7d4cd..afd3435cb6 100644 --- a/examples/browser-use-demo/exercise.py +++ b/examples/browser-use-demo/exercise.py @@ -247,7 +247,7 @@ async def hold_verified(*, cancelled: Callable[[], bool] | None = None) -> None: await asyncio.wait_for(release.wait(), timeout=5) await original_capture(cancelled=cancelled) - current.capture = hold_verified + current.capture = hold_verified # ty: ignore[invalid-assignment] # Test replaces a callable with a controlled fixture. try: await post("/api/approval", {**binding(offered), "approvalId": offered["approval"]["id"], "approved": True}) await asyncio.wait_for(entered.wait(), timeout=5) @@ -277,7 +277,7 @@ async def hold_verified(*, cancelled: Callable[[], bool] | None = None) -> None: assert stopped["result"] == "unverified", "The old agent result survived human editing and Stop" finally: release.set() - current.capture = original_capture + current.capture = original_capture # ty: ignore[invalid-assignment] # Test replaces a callable with a controlled fixture. await post("/api/start", {"taskId": "reservation", "api": "decisions", "mode": "rehearsal"}) offered = await until(lambda s: s["approval"] is not None) await post("/api/take-control", binding(offered)) diff --git a/examples/computer-desktop/guest/install.py b/examples/computer-desktop/guest/install.py index d3c2ac0c61..8463c7d162 100644 --- a/examples/computer-desktop/guest/install.py +++ b/examples/computer-desktop/guest/install.py @@ -108,8 +108,8 @@ def install(root: Path) -> None: b"BP22-LATE-EFI-PASSED", b"BP22-LATE-COMPLETE", ) - if reason or process.returncode or not all(value in outputs["stdout"] for value in checks): - raise RuntimeError(reason or "Installer did not complete its fixed guest checks.") + if process.returncode or not all(value in outputs["stdout"] for value in checks): + raise RuntimeError("Installer did not complete its fixed guest checks.") finally: if process is not None: if process.poll() is None: diff --git a/examples/computer-desktop/guest/setup.py b/examples/computer-desktop/guest/setup.py index f2039c29f4..66498732db 100644 --- a/examples/computer-desktop/guest/setup.py +++ b/examples/computer-desktop/guest/setup.py @@ -16,8 +16,9 @@ import subprocess import urllib.parse import urllib.request -from typing import NamedTuple +from typing import IO, NamedTuple from pathlib import Path +from http.client import HTTPMessage HERE = Path(__file__).resolve().parent # This trusted checkout path also works when the verifier is started with python -I -S. @@ -90,9 +91,8 @@ class Media(NamedTuple): class OfficialRedirects(urllib.request.HTTPRedirectHandler): - # This Python 3.10 bootstrap uses only the standard library, which has no override decorator. - def redirect_request( # pyright: ignore[reportImplicitOverride] - self, req: urllib.request.Request, fp: object, code: int, msg: str, headers: object, newurl: str + def redirect_request( + self, req: urllib.request.Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage, newurl: str ) -> urllib.request.Request | None: url = urllib.parse.urlsplit(newurl) if ( @@ -103,7 +103,7 @@ def redirect_request( # pyright: ignore[reportImplicitOverride] or url.password is not None ): raise ValueError("Debian redirected outside the fixed official download hosts.") - return super().redirect_request(req, fp, code, msg, headers, newurl) # type: ignore[arg-type] + return super().redirect_request(req, fp, code, msg, headers, newurl) def digest(path: Path, algorithm: str = "sha256") -> str: diff --git a/examples/computer-desktop/guest/test_action_admission.py b/examples/computer-desktop/guest/test_action_admission.py index 9ae7360801..2801448064 100644 --- a/examples/computer-desktop/guest/test_action_admission.py +++ b/examples/computer-desktop/guest/test_action_admission.py @@ -48,8 +48,8 @@ def controlled_reply(request: object) -> dict[str, object]: raise TimeoutError("Fixture read was not released.") return {"ok": True} - action.validate = recorded_validate - action.reply = controlled_reply + action.validate = recorded_validate # ty: ignore[invalid-assignment] # Test replaces a callable with a controlled fixture. + action.reply = controlled_reply # ty: ignore[invalid-assignment] # Test replaces a callable with a controlled fixture. action.main() diff --git a/examples/computer-desktop/guest/test_receipt.py b/examples/computer-desktop/guest/test_receipt.py index 7b25e2ec58..a94267609a 100644 --- a/examples/computer-desktop/guest/test_receipt.py +++ b/examples/computer-desktop/guest/test_receipt.py @@ -249,7 +249,7 @@ def guarded_popen(args: list[str], *rest: object, **kwargs: object) -> object: if Path(args[0]) == self.binary: attempted.append(args) raise AssertionError("Test blocked guest spawn") - return original(args, *rest, **kwargs) # type: ignore[call-overload] + return original(args, *rest, **kwargs) # ty: ignore[no-matching-overload] with patch("subprocess.Popen", guarded_popen): with self.assertRaises((ComputerUseError, ValueError, OSError)): diff --git a/examples/demo.py b/examples/demo.py index b08df58b20..8cd45653a3 100755 --- a/examples/demo.py +++ b/examples/demo.py @@ -1,6 +1,7 @@ #!/usr/bin/env -S uv run python from openai import OpenAI +from openai.types.chat import ChatCompletion # gets API Key from environment variable OPENAI_API_KEY client = OpenAI() @@ -49,5 +50,6 @@ ], ) completion = response.parse() +assert isinstance(completion, ChatCompletion) print(response.request_id) print(completion.choices[0].message.content) diff --git a/examples/image_stream.py b/examples/image_stream.py index eab5932534..879c0d0179 100644 --- a/examples/image_stream.py +++ b/examples/image_stream.py @@ -43,7 +43,7 @@ def main() -> None: print(f" 💾 Saved to: {Path(filename).resolve()}") else: - print(f"❓ Unknown event: {event}") # type: ignore[unreachable] + print(f"❓ Unknown event: {event}") if __name__ == "__main__": diff --git a/examples/realtime/audio_util.py b/examples/realtime/audio_util.py index 92219139dd..812fca8596 100644 --- a/examples/realtime/audio_util.py +++ b/examples/realtime/audio_util.py @@ -18,8 +18,6 @@ FORMAT = pyaudio.paInt16 CHANNELS = 1 -# pyright: reportUnknownMemberType=false, reportUnknownVariableType=false, reportUnknownArgumentType=false - def audio_to_pcm16_base64(audio_bytes: bytes) -> bytes: # load the audio file from the byte stream diff --git a/examples/realtime/push_to_talk_app.py b/examples/realtime/push_to_talk_app.py index 84c6489b97..1f25f63f8f 100755 --- a/examples/realtime/push_to_talk_app.py +++ b/examples/realtime/push_to_talk_app.py @@ -1,14 +1,14 @@ #!/usr/bin/env -S uv run -#################################################################### + # Sample TUI app with a push to talk interface to the Realtime API # # If you have `uv` installed and the `OPENAI_API_KEY` # # environment variable set, you can run this example with just # -# # + # `./examples/realtime/push_to_talk_app.py` # -# # + # On Mac, you'll also need `brew install portaudio ffmpeg` # -#################################################################### -# + + # /// script # requires-python = ">=3.10" # dependencies = [ @@ -363,7 +363,7 @@ async def on_key(self, event: events.Key) -> None: ): # The default in the API is that the model will automatically detect when the user has # stopped talking and then start responding itself. - # + # However if we're in manual `turn_detection` mode then we need to # manually tell the model to commit the audio buffer and start responding. # Reserve the shared server buffer before the next K can send. @@ -372,7 +372,7 @@ async def on_key(self, event: events.Key) -> None: partial(self._finish_manual_recording, self._recording), group="realtime-finalization" ) else: - import sounddevice as sd # type: ignore + import sounddevice as sd self._recording = Recording() self._awaiting_new_input = True diff --git a/examples/realtime/test_push_to_talk_app.py b/examples/realtime/test_push_to_talk_app.py index af092c8b30..91e5a3490d 100644 --- a/examples/realtime/test_push_to_talk_app.py +++ b/examples/realtime/test_push_to_talk_app.py @@ -134,7 +134,8 @@ def test_interrupt_discards_device_buffered_audio(app_module: Any) -> None: player.stream.buffered = b"assistant audio that has not reached the speaker" assert player.stop(interrupted_response_id="r1") == [(("r1", "first", 0), 0)] assert not player.stream.emitted - assert not player.stream.buffered + # stop() clears the fake device buffer through abort(); ty retains the earlier literal. + assert not player.stream.buffered # ty: ignore[redundant-condition] @pytest.mark.parametrize("at,expected_frames", [(0.99, 0), (1.01, 240), (1.03, None)]) @@ -990,6 +991,7 @@ async def test_manual_recordings_do_not_share_buffer_after_interruption( module, _ = app_module app = module.RealtimeApp() status = SimpleNamespace(is_recording=False) + def query_one(*_args: Any, **_kwargs: Any) -> SimpleNamespace: return status @@ -1075,10 +1077,13 @@ async def create() -> None: @pytest.mark.asyncio @pytest.mark.parametrize("cancel_before_start", [False, True]) -async def test_pending_manual_finalize_precedes_already_runnable_mic(app_module: Any, cancel_before_start: bool) -> None: +async def test_pending_manual_finalize_precedes_already_runnable_mic( + app_module: Any, cancel_before_start: bool +) -> None: module, _ = app_module app = module.RealtimeApp() status = SimpleNamespace(is_recording=False) + def query_one(*_args: Any, **_kwargs: Any) -> SimpleNamespace: return status diff --git a/examples/responses/websocket.py b/examples/responses/websocket.py index a0b8d7c015..8765762f02 100644 --- a/examples/responses/websocket.py +++ b/examples/responses/websocket.py @@ -188,7 +188,7 @@ def parse_args() -> argparse.Namespace: def parse_tool_name(name: str) -> ToolName: if name not in {"get_sku_inventory", "get_supplier_eta", "get_quality_alerts"}: raise ValueError(f"Unsupported tool requested: {name}") - return cast(ToolName, name) + return name def parse_sku_arguments(raw_arguments: str) -> SKUArguments: diff --git a/examples/video.py b/examples/video.py index b1d6528028..ad9b681a28 100644 --- a/examples/video.py +++ b/examples/video.py @@ -8,7 +8,8 @@ async def main() -> None: - video = await client.videos.create_and_poll( # pyright: ignore[reportDeprecated] + # This example intentionally demonstrates the deprecated video helper. + video = await client.videos.create_and_poll( # ty: ignore[deprecated] model="sora-2", prompt="A video of the words 'Thank you' in sparkling letters", ) diff --git a/pyproject.toml b/pyproject.toml index 6b20739732..a0cc9b8791 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ vertex = ["google-auth[requests]>=2.36,<3"] [dependency-groups] dev = [ - "mypy==2.3.1", + "ty==0.0.87", "pytest>=9.0.3", "pytest-asyncio>=1.4.0", "Pillow==12.3.0", @@ -137,7 +137,6 @@ include = [ "/.node-version", "/pnpm-lock.yaml", "/pnpm-workspace.yaml", - "/mypy.ini", "bin/*", "examples/*", "scripts/*", @@ -161,115 +160,55 @@ filterwarnings = [ [tool.inline-snapshot] format-command="ruff format --stdin-filename {filename}" -[tool.pyright] -# this enables practically every flag given by pyright. -# there are a couple of flags that are still disabled by -# default in strict mode as they are experimental and niche. -typeCheckingMode = "strict" -pythonVersion = "3.10" +# Repository checks use ty; published annotations remain checker-independent. +[tool.ty.environment] +python-version = "3.10" +[tool.ty.src] exclude = [ "examples/browser/", "examples/browser-use-demo/", "examples/computer-desktop/", - "_dev", - "node_modules", - ".pnpm-store", - ".venv", - ".venv-pydantic-v1", - # Contributors may still have an environment from before the uv migration. - ".nox", - ".git", - "tests/respx2", - "src/openai/_vendor", - # Loaded in Hatchling's isolated build environment. - "scripts/hatch_metadata.py", - - # uses inline `uv` script dependencies - # which means it can't be type checked - "examples/realtime/audio_util.py", - "examples/realtime/push_to_talk_app.py", + "_dev", "node_modules", ".pnpm-store", ".venv", ".venv-pydantic-v1", ".nox", + "tests/respx2", "src/openai/_vendor", "scripts/hatch_metadata.py", + "examples/realtime/audio_util.py", "examples/realtime/push_to_talk_app.py", ] -reportImplicitOverride = true -reportOverlappingOverload = false - -reportImportCycles = false -reportPrivateUsage = false +[tool.ty.rules] +unused-type-ignore-comment = "error" +unused-ignore-comment = "error" +redundant-cast = "error" -[tool.mypy] -pretty = true -show_error_codes = true +[[tool.ty.overrides]] +include = ["tests/test_lazy_imports.py"] +[tool.ty.overrides.rules] +# Reexports retain callable/class subtypes that assert_type cannot spell exactly. +assert-type-unspellable-subtype = "ignore" -# Exclude _files.py because mypy isn't smart enough to apply -# the correct type narrowing and as this is an internal module -# it's fine to just use Pyright. -# -# We also exclude our `tests` as mypy doesn't always infer -# types correctly and Pyright will still catch any type errors. -# -# realtime examples use inline `uv` script dependencies -# which means it can't be type checked -exclude = [ - 'examples/browser/', - 'examples/browser-use-demo/', - 'examples/computer-desktop/', - 'src/openai/_files.py', - 'node_modules/.*', - '\.pnpm-store/.*', - 'src/openai/_vendor/.*', - 'scripts/hatch_metadata.py', - '_dev/.*.py', - 'tests/.*', - 'src/openai/_utils/_logs.py', - 'examples/realtime/audio_util.py', - 'examples/realtime/push_to_talk_app.py', - # Optional Playwright examples are checked with their separate dependency environment. +[[tool.ty.overrides]] +include = [ + "src/openai/_exceptions.py", + "src/openai/lib/streaming/responses/_events.py", + "src/openai/types/chat/parsed_chat_completion.py", + "src/openai/types/chat/parsed_function_tool_call.py", + "src/openai/types/evals/runs/output_item_list_response.py", + "src/openai/types/evals/runs/output_item_retrieve_response.py", + "tests/test_models.py", ] +[tool.ty.overrides.rules] +# These Pydantic models and HTTP exceptions intentionally narrow mutable fields. +# Preserve their existing contract without suppressing unrelated overrides. +invalid-mutable-override = "ignore" -strict_equality = true -implicit_reexport = true -check_untyped_defs = true -no_implicit_optional = true - -warn_return_any = true -warn_unreachable = true -warn_unused_configs = true - -# Turn these options off as it could cause conflicts -# with the Pyright options. -warn_unused_ignores = false -warn_redundant_casts = false - -disallow_any_generics = true -disallow_untyped_defs = true -disallow_untyped_calls = true -disallow_subclassing_any = true -disallow_incomplete_defs = true -disallow_untyped_decorators = true -cache_fine_grained = true - -# By default, mypy reports an error if you assign a value to the result -# of a function call that doesn't return anything. We do this in our test -# cases: -# ``` -# result = ... -# assert result is None -# ``` -# Changing this codegen to make mypy happy would increase complexity -# and would not be worth it. -disable_error_code = "func-returns-value,overload-cannot-match" - -# https://github.com/python/mypy/issues/12162 -[[tool.mypy.overrides]] -module = "black.files.*" -ignore_errors = true -ignore_missing_imports = true +[[tool.ty.overrides]] +include = [ + "tests/**", "src/openai/resources/**", + "src/openai/lib/_assistants_*.py", +] +[tool.ty.overrides.rules] +# Tests exercise deprecated entrypoints; their implementations and reexports must remain available. +deprecated = "ignore" -# Preserve the existing _files.py exclusion when mypy follows its imports. -[[tool.mypy.overrides]] -module = "openai._files" -follow_imports = "silent" [tool.ruff] extend-exclude = ["tests/respx2", "src/openai/_vendor"] diff --git a/scripts/bootstrap b/scripts/bootstrap index b88bfb0d08..462c50d955 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -22,5 +22,3 @@ fi echo "==> Installing Python dependencies…" uv sync --locked --all-extras - -./scripts/bootstrap-node diff --git a/scripts/bootstrap-node b/scripts/bootstrap-node index b2179550ed..96223efbf2 100755 --- a/scripts/bootstrap-node +++ b/scripts/bootstrap-node @@ -3,7 +3,7 @@ set -euo pipefail cd "$(dirname "$0")/.." if ! command -v node >/dev/null 2>&1; then - echo 'Node.js is required. Install the version in .node-version, then rerun ./scripts/bootstrap.' >&2 + echo 'Node.js is required. Install the version in .node-version, then rerun ./scripts/bootstrap-node.' >&2 exit 1 fi node scripts/utils/node-tooling.cjs --check-node diff --git a/scripts/castiron/generated-files.json b/scripts/castiron/generated-files.json index f8524546c7..6136c8513d 100644 --- a/scripts/castiron/generated-files.json +++ b/scripts/castiron/generated-files.json @@ -7,11 +7,11 @@ }, "src/openai/__init__.py": { "mode": "100644", - "sha256": "7cc1c0f0587ac77b0651af9ab2eeb21d6bfd516fe364d883ca11474b0c2a2552" + "sha256": "c9f81677ff05227f7051ef9e91729a7f2e566c506c839c5779b7f28a288bb77b" }, "src/openai/_client.py": { "mode": "100644", - "sha256": "5d15ec6b96667bbce3d926f1d7a0eede0d88876773193c6f92e9bf4cd63239d0" + "sha256": "4ed7e53a2a8282ca001358386a6e6cd689cb1c42e9d31ea01828399fbd4a0ee8" }, "src/openai/_data_residency.py": { "mode": "100644", @@ -207,11 +207,11 @@ }, "src/openai/resources/audio/transcriptions.py": { "mode": "100644", - "sha256": "a0ffd448d9c0243cbc4ad4bf0e05040cb1b8b9cf9e294517eb74197700a6e21e" + "sha256": "14bcfdb8638f6b1aa5847441183cd53277ea32038112f7db90880e1daa456cab" }, "src/openai/resources/audio/translations.py": { "mode": "100644", - "sha256": "2d0ba2a0c4e8235759793e4af0d98dd2e845a26b0dc4dd4094ee3a47aa700549" + "sha256": "4653c956a5e3a49462d13f902aa6e6d14da5f8be6a5b6bf2fbcd28ba1e6c5ad7" }, "src/openai/resources/audio/voice_consents.py": { "mode": "100644", @@ -339,7 +339,7 @@ }, "src/openai/resources/beta/assistants.py": { "mode": "100644", - "sha256": "3b3fed19ca0b8c74082ff2387b73f33a62822e60abee55b93dc33f527fbe9318" + "sha256": "5676fd2134e7cfa2d91dceda7894b692256853ab5a44bd9c16f837f161b2026f" }, "src/openai/resources/beta/beta.py": { "mode": "100644", @@ -383,7 +383,7 @@ }, "src/openai/resources/beta/threads/messages.py": { "mode": "100644", - "sha256": "7cea4c0d6f5ee498333913e6baeaef0eac3adc9381b9ce34fabff1efe4b1cfae" + "sha256": "369a9d84911dcdf15cacae43706d8b40e47adb52e4f035a2089f7f49abf60882" }, "src/openai/resources/beta/threads/runs/__init__.py": { "mode": "100644", @@ -391,15 +391,15 @@ }, "src/openai/resources/beta/threads/runs/runs.py": { "mode": "100644", - "sha256": "112765c8d6358e7b11afb412b5b67589363b7dbb9c7f3721bdc714fb6f1f0696" + "sha256": "c8a082b6af6870571534929c095aa1416e645c82f9155c59f295162d99601b9a" }, "src/openai/resources/beta/threads/runs/steps.py": { "mode": "100644", - "sha256": "82f0d57648c18adf36f95410d1021e791b12195549d612e7bf1f942e53545ede" + "sha256": "07b1d4547574fd86174f640554956a3c2952bed3aaea9569f32b07d68b1711ae" }, "src/openai/resources/beta/threads/threads.py": { "mode": "100644", - "sha256": "652f35ffa56651f81e8b7d3b2dfd1a4bb6728bd1fd7c5489c1586e5394bd21a8" + "sha256": "888c4757f56ac4ad15e49ac3a9de4762f7fc4731abe93d9b7f822c50565ae3c0" }, "src/openai/resources/chat/__init__.py": { "mode": "100644", @@ -495,7 +495,7 @@ }, "src/openai/resources/files.py": { "mode": "100644", - "sha256": "4d07e7fd7e821a92b4e55d985336c0a2b4495aa7b682b82dd1f37557171c807a" + "sha256": "4e4de9907870c1b6f3c5430342fb49e41d48b9e62eaa062a588fe08e4f6ff5ad" }, "src/openai/resources/fine_tuning/__init__.py": { "mode": "100644", @@ -523,7 +523,7 @@ }, "src/openai/resources/fine_tuning/checkpoints/permissions.py": { "mode": "100644", - "sha256": "d19e7661ef9f4f1b4fae8d448a854f1445aa08fce37045d179654d622ed52c32" + "sha256": "f3a867328d2b98e0fff9ecc7b501b60fad0115cc6cbb64055c3ce4a4a1c762e0" }, "src/openai/resources/fine_tuning/fine_tuning.py": { "mode": "100644", @@ -543,7 +543,7 @@ }, "src/openai/resources/images.py": { "mode": "100644", - "sha256": "bc0bfc7d1a96b6c14761215ff2333fd58922d835e04956a2fa5157ea41b68dc9" + "sha256": "f8f5376eeda7b45a90179eb287066447fce19ed761d313de5ab4c59df620b659" }, "src/openai/resources/live/__init__.py": { "mode": "100644", @@ -699,7 +699,7 @@ }, "src/openai/resources/videos.py": { "mode": "100644", - "sha256": "d505c37b6faae6cb3de9dabab651edd2ea5ee8eeac2134a0db94bf568f3a77c8" + "sha256": "1703210555717144469ae1e5578625f4385ec8b2fa1140a7c7c1a7f521027d4c" }, "src/openai/resources/webhooks/__init__.py": { "mode": "100644", @@ -2551,7 +2551,7 @@ }, "src/openai/types/beta/beta_response_custom_tool_call_item.py": { "mode": "100644", - "sha256": "8620f5865a9ea00bd9d422818ac8b1cea42fc96fd42f0d32016bd19d1f76d0fd" + "sha256": "24bf113bb97d6ef4436709f545b8a1e904b983743f2e583f39fa2a756e634165" }, "src/openai/types/beta/beta_response_custom_tool_call_output.py": { "mode": "100644", @@ -2559,7 +2559,7 @@ }, "src/openai/types/beta/beta_response_custom_tool_call_output_item.py": { "mode": "100644", - "sha256": "a9b54909530031f3f8bd996a3cbeb3677dad06e9fc1166c094b3cec7ac4b4355" + "sha256": "e2d5ba522339b8b01f550623c92c613b4b6963692d4b724930dd0f0cda2e3c13" }, "src/openai/types/beta/beta_response_custom_tool_call_output_param.py": { "mode": "100644", @@ -2663,7 +2663,7 @@ }, "src/openai/types/beta/beta_response_function_tool_call_item.py": { "mode": "100644", - "sha256": "55be8db78553ab612114cddec709010cae008ec2450fd33020476b85085f6b70" + "sha256": "aee4f2768dc2856f305cc8ce9e6a44126cafb04701280866957f5384e3c732db" }, "src/openai/types/beta/beta_response_function_tool_call_output_item.py": { "mode": "100644", @@ -4263,11 +4263,11 @@ }, "src/openai/types/evals/runs/output_item_list_response.py": { "mode": "100644", - "sha256": "69a21112186eb69f19466d928baf88960bf18d76bfea90d001596e22e041a887" + "sha256": "db6b6596afb956f5791985f704d171e0ddf3fb076e283d1d6784dfe061fe2d6e" }, "src/openai/types/evals/runs/output_item_retrieve_response.py": { "mode": "100644", - "sha256": "7b1e413612ad9bc8bdd6b2807613cc6f996435af8e9ad6c9040c47a831e1a805" + "sha256": "9f1b0a1988719b137dd874656c1688a2a3d47be0a45abaf3d687cd71ab964232" }, "src/openai/types/file_chunking_strategy.py": { "mode": "100644", @@ -6199,7 +6199,7 @@ }, "src/openai/types/responses/response_custom_tool_call_item.py": { "mode": "100644", - "sha256": "54ce5dd469ab9c7d8f65157834a7da4cec241bee1a575d09a827dfa0960f8de1" + "sha256": "186fa4aec8d6aa3e6fba167380c5749f7717f14a21d38aee73b4a6ff1df90e2a" }, "src/openai/types/responses/response_custom_tool_call_output.py": { "mode": "100644", @@ -6207,7 +6207,7 @@ }, "src/openai/types/responses/response_custom_tool_call_output_item.py": { "mode": "100644", - "sha256": "b7603a302b802ed07c9c563b5c2bf66df1f8fe1cbc0a56ce9e05bca56463c3fe" + "sha256": "ec14dd5e25712e9244da6138027ded2611d409d0ffe6946a76ddb48ccd7aa975" }, "src/openai/types/responses/response_custom_tool_call_output_param.py": { "mode": "100644", @@ -6311,7 +6311,7 @@ }, "src/openai/types/responses/response_function_tool_call_item.py": { "mode": "100644", - "sha256": "6e3f8258ece7112249d286b0756c20e7cc51b567f611bcf3435e15325906b5ac" + "sha256": "3c9966c1135de25afb0be912d669ea9af8b93aa0c7cab045b9c0be4028180c68" }, "src/openai/types/responses/response_function_tool_call_output_item.py": { "mode": "100644", @@ -7579,15 +7579,15 @@ }, "tests/api_resources/audio/test_speech.py": { "mode": "100644", - "sha256": "3e482a4f2f83c383e5dc52a12d3e6e7ef4f458926ac0304a46255f19165909d5" + "sha256": "3b1f664e4d06d4fd9c5f6335aefe9ca4e0d1de9f807df6f44018bdf7b16bd616" }, "tests/api_resources/audio/test_transcriptions.py": { "mode": "100644", - "sha256": "0d545df7745a465fb641c7b3f9c51fed837c5810ee051191ecd2ea2272344d17" + "sha256": "85a23add54d1cb87889d6f89d918921ab52ddbc86ff559228c7b4c54e17d43a3" }, "tests/api_resources/audio/test_translations.py": { "mode": "100644", - "sha256": "73ced6a2e0c145127c61738b0e96152425f19654d7e7ba46254fecb0b34e288d" + "sha256": "20c5179c4517302c41c0dda892e867cee7de36d96e6f54bffaf350e3e9c01b85" }, "tests/api_resources/audio/test_voice_consents.py": { "mode": "100644", @@ -7651,11 +7651,11 @@ }, "tests/api_resources/beta/agents/sessions/test_artifacts.py": { "mode": "100644", - "sha256": "3ee94d6ec93b2517595c8d01bb548c69e92cba58df3aa1931498acea07394391" + "sha256": "09eefba15ca2dea10bf2af56847b93edea1aecd032b0cafea1d16d01e8d03541" }, "tests/api_resources/beta/agents/sessions/test_events.py": { "mode": "100644", - "sha256": "3502e64c7f92f2e6370a328ff53e069c39448ed982b507a233b46314fa0de89a" + "sha256": "2dfbe82e4ecab75b325978f373ffa1b36dbe95f35f9bbcd9f1a5a0f3653002cb" }, "tests/api_resources/beta/agents/sessions/test_items.py": { "mode": "100644", @@ -7691,7 +7691,7 @@ }, "tests/api_resources/beta/agents/test_sessions.py": { "mode": "100644", - "sha256": "10a9f8cbd1fda1b32b4bf7a0ac422073e82463b9dd1f9151d159951ea47005d8" + "sha256": "42d73e43adfc9dff9ac4b0742dc16e6d97f9f67b2a83da62304193da0cf48077" }, "tests/api_resources/beta/agents/test_vaults.py": { "mode": "100644", @@ -7735,15 +7735,15 @@ }, "tests/api_resources/beta/test_assistants.py": { "mode": "100644", - "sha256": "6d2dbfd3d031da2002b57801af6d3a1334e0b96bc71216809096dc62a4007309" + "sha256": "815848a1301fb97010cf812684dde925fe668bf0e18efaf3784425ea57e2d43f" }, "tests/api_resources/beta/test_responses.py": { "mode": "100644", - "sha256": "23d419d2b16d3ddda6de6eae6d29ecb649521f94df8dcc27537d857dd4d8240b" + "sha256": "61ab88121c15f8d0b5177e828a93275c175a3894df82379601b394a45ab8173a" }, "tests/api_resources/beta/test_threads.py": { "mode": "100644", - "sha256": "79ca1c8bd941189b2a6e3c27ea0b5725bb3c0c0d25eb47bc92b19a4bb05056e3" + "sha256": "ecaa08aae2d6cd8aa66860fc982f5e25d6ee074343067848d367cd3e368c834b" }, "tests/api_resources/beta/threads/__init__.py": { "mode": "100644", @@ -7755,15 +7755,15 @@ }, "tests/api_resources/beta/threads/runs/test_steps.py": { "mode": "100644", - "sha256": "30f927248ed5c7dca3da9a9f96d6cb4e788bd8db0e196399f8b931fe647bcc87" + "sha256": "5daa642a041062021b189cce879729935c95dcb383eca79bf47974c47a2386d2" }, "tests/api_resources/beta/threads/test_messages.py": { "mode": "100644", - "sha256": "580d1c043429bd08b2a64b030f4487591a76440db09b34da2c5ad6b1b8ecca08" + "sha256": "e265ad869d5af37210a0d8824fb77acabc3c1d5f440a4387b472fb92147c224d" }, "tests/api_resources/beta/threads/test_runs.py": { "mode": "100644", - "sha256": "13b79eb9de458f8b9cd9384562e38816088698b9bf80f0490b540b753270beb4" + "sha256": "fbf28555b95fba2cb5f0ba321cf87eef77e80be972e10f04edf90c97eb736235" }, "tests/api_resources/chat/__init__.py": { "mode": "100644", @@ -7779,7 +7779,7 @@ }, "tests/api_resources/chat/test_completions.py": { "mode": "100644", - "sha256": "dd1d25a75da6c5824d2ef05bce57d61a82dcbc22ce81a55fe77f6d1c12030308" + "sha256": "7196f2bf051593ea0dd6e0e90f2db9105c4428a21e531530dca4eeebe65ff860" }, "tests/api_resources/containers/__init__.py": { "mode": "100644", @@ -7791,7 +7791,7 @@ }, "tests/api_resources/containers/files/test_content.py": { "mode": "100644", - "sha256": "145d3bd180f9f8a944a0a3e5214cab92148f38d0b9051aac8069fcbaea28cb79" + "sha256": "6ae48b076302365f4c11b412795ad0f25ffbccca14a8510f1931a78069de3b9b" }, "tests/api_resources/containers/test_files.py": { "mode": "100644", @@ -7839,7 +7839,7 @@ }, "tests/api_resources/fine_tuning/checkpoints/test_permissions.py": { "mode": "100644", - "sha256": "239a933b3fc9a6fc3e9ec37306e4c0575cf7e0d64a34bc7107fe27c0bc12035a" + "sha256": "6fdff2dc6dba115c8f089c798d951722c92adf726260538345e49646e293bbdd" }, "tests/api_resources/fine_tuning/jobs/__init__.py": { "mode": "100644", @@ -7863,7 +7863,7 @@ }, "tests/api_resources/live/test_sessions.py": { "mode": "100644", - "sha256": "751f651775f0547d6c236d8d6bc44bbe00ab195d0c2202d9d08d29c8ed4a3bfc" + "sha256": "61139451d9ad16406b15d3085aaf82f2b9fe8fcd5bd253796e4d6f628a39be30" }, "tests/api_resources/live/test_sideband.py": { "mode": "100644", @@ -7875,7 +7875,7 @@ }, "tests/api_resources/realtime/test_calls.py": { "mode": "100644", - "sha256": "14b334e6eb6dc9e5c8bd760957a43bdebce9c97957d88354806e641deedc22f1" + "sha256": "6ecf9fd59592480ebbc508b15861ef935e367e4815d04c38235395109a374841" }, "tests/api_resources/realtime/test_client_secrets.py": { "mode": "100644", @@ -7923,7 +7923,7 @@ }, "tests/api_resources/skills/test_content.py": { "mode": "100644", - "sha256": "dbb7a47695af6752b02a5186ef1cd274f8bd34d7cde1a32451c67b6d62396e1f" + "sha256": "33f2046705d19082a003247219155988f440d32b2d8afcebac8e79410f48f830" }, "tests/api_resources/skills/test_versions.py": { "mode": "100644", @@ -7935,7 +7935,7 @@ }, "tests/api_resources/skills/versions/test_content.py": { "mode": "100644", - "sha256": "9867f7f30c65d123cf49fd3155ce9c1bf7b3b0c644b39ceb7d4f2b9a9aa815dd" + "sha256": "8c23ddb935b58bc8590b90f3eea8cd98e1a2e3f0b8c817790210c1ca06ab0182" }, "tests/api_resources/test_batches.py": { "mode": "100644", @@ -7943,7 +7943,7 @@ }, "tests/api_resources/test_completions.py": { "mode": "100644", - "sha256": "387eceefc82e3fab0fcd374b21615bac80a5b9a9f17ac28c9edeb1b1c1053295" + "sha256": "852f84181e3238cd2e58fbe28ad98fdd4b5f501b5ac6d3366c1eca6e41384f98" }, "tests/api_resources/test_containers.py": { "mode": "100644", @@ -7971,11 +7971,11 @@ }, "tests/api_resources/test_files.py": { "mode": "100644", - "sha256": "2b747d201be8a0db9eb64089e0974ce14d7d9078ac1f3d2d451db53c67b803e0" + "sha256": "839d776d460d80d647826b086c7a932b84fb1071204b16da0c94bf0a42ee5eab" }, "tests/api_resources/test_images.py": { "mode": "100644", - "sha256": "39b8d0e03206abc79df8eb4c3fe5c6a928dfb22d2ccaa2423e0a0db011e2b049" + "sha256": "ebd279e1c7d8c8bd3c8148d1aadbeb7dc1ba43a6e2ee7396653e37563e743f3b" }, "tests/api_resources/test_live.py": { "mode": "100644", @@ -7995,7 +7995,7 @@ }, "tests/api_resources/test_responses.py": { "mode": "100644", - "sha256": "94c39dd77ad63999168f3e55587f160fde2ec27503ba361ae6c6d5faa206621d" + "sha256": "2e70ff147b7fd65bd00f2625434cc65aa1959bc15aeee013ecfba345ca177d32" }, "tests/api_resources/test_skills.py": { "mode": "100644", @@ -8011,7 +8011,7 @@ }, "tests/api_resources/test_videos.py": { "mode": "100644", - "sha256": "bcc55dc2c7b47d6998ac977b4b6b073ce62bd6f963496f312ff350e9ee1382c9" + "sha256": "c857cf011dee1d3df0482a738fb3d3dbe20d858f56c1af8722c7c9d47abdf9f3" }, "tests/api_resources/test_webhooks.py": { "mode": "100644", diff --git a/scripts/check-python-version-policy.py b/scripts/check-python-version-policy.py index ae57734836..5d149c0cf6 100644 --- a/scripts/check-python-version-policy.py +++ b/scripts/check-python-version-policy.py @@ -83,7 +83,11 @@ def main() -> None: classifiers = re.findall(r'"Programming Language :: Python :: (3\.\d+)"', pyproject) require(tuple(classifiers) == SUPPORTED, f"Unexpected Python classifiers: {classifiers}") - require(f'pythonVersion = "{MINIMUM}"' in pyproject, "Pyright does not target the minimum Python") + require(f'python-version = "{MINIMUM}"' in pyproject, "ty does not target the minimum Python") + require( + f'"pythonVersion": "{MINIMUM}"' in (ROOT / "scripts/pyrightconfig.breaking-changes.json").read_text(), + "Consumer compatibility check does not target the minimum Python", + ) require(f'target-version = "py{MINIMUM.replace(".", "")}"' in pyproject, "Ruff does not target the minimum Python") require(python_version.startswith(f"{MINIMUM}."), f".python-version is not on Python {MINIMUM}: {python_version}") require(f"Python {MINIMUM}+" in readme, "README introduction does not state the minimum Python") diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 25b6aa485f..bfb8d52858 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -19,6 +19,6 @@ for PATHSPEC in "${TEST_PATHS[@]}"; do git checkout "$1" -- "${PATHSPEC}" 2>/dev/null || true done -# Instead of running the tests, use the linter to check if an -# older test is no longer compatible with the latest SDK. -PYRIGHT_PROJECT=scripts/pyrightconfig.breaking-changes.json ./scripts/lint +# Check unchanged previous-version callers with Pyright. Repository development +# uses ty; this isolated gate protects consumers who use another checker. +uv run --locked --all-extras scripts/run-pyright diff --git a/scripts/fixtures/computer_use_smoke.py b/scripts/fixtures/computer_use_smoke.py index 2b45eb7bc7..094e7a1ad0 100644 --- a/scripts/fixtures/computer_use_smoke.py +++ b/scripts/fixtures/computer_use_smoke.py @@ -169,7 +169,8 @@ async def invoke(value: Any) -> Any: final = await invoke( runner.run( client, - {**params, "input": fresh}, + # The synthetic request is assembled dynamically from the fixture above. + {**params, "input": fresh}, # ty: ignore[invalid-argument-type] ledger=ledger( "package-smoke", adapt(save), diff --git a/scripts/lint b/scripts/lint index 60142f9f18..80076dee1d 100755 --- a/scripts/lint +++ b/scripts/lint @@ -10,8 +10,7 @@ if [ "${1:-}" = "--fix" ]; then else echo "==> Running lints" uv run --locked --all-extras ruff check . - uv run --locked --all-extras scripts/run-pyright - uv run --locked --all-extras mypy . + uv run --locked --all-extras ty check fi echo "==> Making sure it imports" diff --git a/scripts/pyrightconfig.breaking-changes.json b/scripts/pyrightconfig.breaking-changes.json index 87bfd3bbc0..c58d137d23 100644 --- a/scripts/pyrightconfig.breaking-changes.json +++ b/scripts/pyrightconfig.breaking-changes.json @@ -1,4 +1,21 @@ { - "extends": "../pyproject.toml", - "reportDeprecated": false + "include": [ + "../tests/api_resources", + "../tests/test_client.py", + "../tests/test_response.py", + "../tests/test_legacy_response.py" + ], + "typeCheckingMode": "strict", + "pythonVersion": "3.10", + "reportImplicitOverride": true, + "reportOverlappingOverload": false, + "reportImportCycles": false, + "reportPrivateUsage": false, + "reportDeprecated": false, + "executionEnvironments": [ + { + "root": "..", + "extraPaths": ["../src"] + } + ] } diff --git a/scripts/pyrightconfig.browser-demo.json b/scripts/pyrightconfig.browser-demo.json deleted file mode 100644 index a667ad08bf..0000000000 --- a/scripts/pyrightconfig.browser-demo.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../pyproject.toml", - "include": [ - "../examples/browser-use-demo" - ], - "exclude": [], - "extraPaths": [ - "../examples/browser-use-demo", - "../examples/browser", - "../src" - ] -} diff --git a/scripts/pyrightconfig.browser-example.json b/scripts/pyrightconfig.browser-example.json deleted file mode 100644 index 194b8c455f..0000000000 --- a/scripts/pyrightconfig.browser-example.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../pyproject.toml", - "include": [ - "../examples/browser" - ], - "exclude": [], - "extraPaths": [ - "../examples/browser", - "../src" - ] -} diff --git a/scripts/pyrightconfig.computer-example.json b/scripts/pyrightconfig.computer-example.json deleted file mode 100644 index 80c09bdd8e..0000000000 --- a/scripts/pyrightconfig.computer-example.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../pyproject.toml", - "include": [ - "../examples/computer-desktop" - ], - "exclude": [], - "extraPaths": [ - "../examples/computer-desktop", - "../examples/computer-desktop/guest", - "../src" - ] -} diff --git a/scripts/run-pyright b/scripts/run-pyright index 4ce362cc6b..3e2fe0a8c4 100755 --- a/scripts/run-pyright +++ b/scripts/run-pyright @@ -4,9 +4,9 @@ set -euo pipefail cd "$(dirname "$0")/.." -CONFIG=${PYRIGHT_PROJECT:-pyproject.toml} +CONFIG=${PYRIGHT_PROJECT:-scripts/pyrightconfig.breaking-changes.json} if ! command -v node >/dev/null 2>&1; then - echo 'Node.js is missing. Follow CONTRIBUTING.md, then run ./scripts/bootstrap.' >&2 + echo 'Node.js is missing. Follow CONTRIBUTING.md, then run ./scripts/bootstrap-node.' >&2 exit 1 fi exec node scripts/utils/node-tooling.cjs pyright -p "$CONFIG" "$@" diff --git a/scripts/test b/scripts/test index 68546c7c4d..7169051c4b 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}./scripts/bootstrap${NC}" + echo -e " \$ ${YELLOW}./scripts/steady/install${NC}" echo -e " \$ ${YELLOW}./scripts/mock path/to/your.openapi.yml${NC}" echo diff --git a/scripts/utils/node-tooling.cjs b/scripts/utils/node-tooling.cjs index b81bfe23ab..e98ceb2d62 100644 --- a/scripts/utils/node-tooling.cjs +++ b/scripts/utils/node-tooling.cjs @@ -8,7 +8,7 @@ const root = path.resolve(__dirname, '../..'); const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); function fail(message) { - console.error(`${message}\nRun ./scripts/bootstrap after installing the versions documented in CONTRIBUTING.md.`); + console.error(`${message}\nRun ./scripts/bootstrap-node after installing the versions documented in CONTRIBUTING.md.`); process.exit(1); } diff --git a/src/openai/__init__.py b/src/openai/__init__.py index e5c97c758c..3d6c4a262f 100644 --- a/src/openai/__init__.py +++ b/src/openai/__init__.py @@ -225,60 +225,57 @@ def __dir__() -> list[str]: class _ModuleClient(OpenAI): - # Note: we have to use type: ignores here as overriding class members - # with properties is technically unsafe but it is fine for our use case - - @property # type: ignore + @property @override def api_key(self) -> str | None: return api_key - @api_key.setter # type: ignore - def api_key(self, value: str | None) -> None: # type: ignore - global api_key + @api_key.setter + def api_key(self, value: str | None) -> None: # ty: ignore[invalid-property-type-override] + global api_key # ty: ignore[invalid-property-type-override] api_key = value - @property # type: ignore + @property @override def admin_api_key(self) -> str | None: return admin_api_key - @admin_api_key.setter # type: ignore - def admin_api_key(self, value: str | None) -> None: # type: ignore + @admin_api_key.setter + def admin_api_key(self, value: str | None) -> None: global admin_api_key admin_api_key = value - @property # type: ignore + @property @override def organization(self) -> str | None: return organization - @organization.setter # type: ignore - def organization(self, value: str | None) -> None: # type: ignore + @organization.setter + def organization(self, value: str | None) -> None: global organization organization = value - @property # type: ignore + @property @override def project(self) -> str | None: return project - @project.setter # type: ignore - def project(self, value: str | None) -> None: # type: ignore + @project.setter + def project(self, value: str | None) -> None: global project project = value - @property # type: ignore + @property @override def webhook_secret(self) -> str | None: return webhook_secret - @webhook_secret.setter # type: ignore - def webhook_secret(self, value: str | None) -> None: # type: ignore + @webhook_secret.setter + def webhook_secret(self, value: str | None) -> None: global webhook_secret webhook_secret = value @@ -293,70 +290,70 @@ def base_url(self) -> _httpx.URL: @base_url.setter def base_url(self, url: _httpx.URL | str) -> None: - super().base_url = url # type: ignore[misc] + # The module proxy forwards to the existing base property setter. + super().base_url = url # ty: ignore[invalid-assignment] - @property # type: ignore + @property @override def timeout(self) -> float | Timeout | None: return timeout - @timeout.setter # type: ignore - def timeout(self, value: float | Timeout | None) -> None: # type: ignore + @timeout.setter + def timeout(self, value: float | Timeout | None) -> None: global timeout timeout = value - @property # type: ignore + @property @override def max_retries(self) -> int: return max_retries - @max_retries.setter # type: ignore - def max_retries(self, value: int) -> None: # type: ignore + @max_retries.setter + def max_retries(self, value: int) -> None: global max_retries max_retries = value - @property # type: ignore + @property @override def _custom_headers(self) -> _t.Mapping[str, str] | None: return default_headers - @_custom_headers.setter # type: ignore - def _custom_headers(self, value: _t.Mapping[str, str] | None) -> None: # type: ignore + @_custom_headers.setter + def _custom_headers(self, value: _t.Mapping[str, str] | None) -> None: global default_headers default_headers = value - @property # type: ignore + @property @override def _custom_query(self) -> _t.Mapping[str, object] | None: return default_query - @_custom_query.setter # type: ignore - def _custom_query(self, value: _t.Mapping[str, object] | None) -> None: # type: ignore + @_custom_query.setter + def _custom_query(self, value: _t.Mapping[str, object] | None) -> None: global default_query default_query = value - @property # type: ignore + @property @override def _client(self) -> _httpx.Client: return http_client or super()._client - @_client.setter # type: ignore - def _client(self, value: _httpx.Client) -> None: # type: ignore + @_client.setter + def _client(self, value: _httpx.Client) -> None: global http_client http_client = value -class _AzureModuleClient(_ModuleClient, AzureOpenAI): # type: ignore - ... +class _AzureModuleClient(_ModuleClient, AzureOpenAI): ... -class _BedrockModuleClient(_ModuleClient, BedrockOpenAI): # type: ignore - @property # type: ignore +class _BedrockModuleClient(_ModuleClient, BedrockOpenAI): + @property @override def api_key( self, @@ -365,7 +362,7 @@ def api_key( return BedrockModuleClient_api_key(self) - @api_key.setter # type: ignore + @api_key.setter def api_key( self, value: str | None, @@ -395,7 +392,7 @@ def _legacy_auth_configuration( return BedrockModuleClient_legacy_auth_configuration(_runtime_cast(_RuntimeAny, super()).__thisclass__, self) -class _AmbiguousModuleClientUsageError(OpenAIError): # type: ignore[reportUnusedClass] +class _AmbiguousModuleClientUsageError(OpenAIError): def __init__( self, ) -> None: @@ -406,19 +403,19 @@ def __init__( return AmbiguousModuleClientUsageError_init(_runtime_cast(_RuntimeAny, super()).__thisclass__, self) -def _has_openai_credentials() -> bool: # type: ignore[reportUnusedFunction] +def _has_openai_credentials() -> bool: from .lib._module_runtime import has_openai_credentials return has_openai_credentials() -def _has_azure_credentials() -> bool: # type: ignore[reportUnusedFunction] +def _has_azure_credentials() -> bool: from .lib._module_runtime import has_azure_credentials return has_azure_credentials() -def _has_azure_ad_credentials() -> bool: # type: ignore[reportUnusedFunction] +def _has_azure_ad_credentials() -> bool: from .lib._module_runtime import has_azure_ad_credentials return has_azure_ad_credentials() @@ -427,13 +424,13 @@ def _has_azure_ad_credentials() -> bool: # type: ignore[reportUnusedFunction] _client: OpenAI | None = None -def _load_client() -> OpenAI: # type: ignore[reportUnusedFunction] +def _load_client() -> OpenAI: from .lib._module_runtime import load_client return load_client() -def _reset_client() -> None: # type: ignore[reportUnusedFunction] +def _reset_client() -> None: global _client _client = None diff --git a/src/openai/_base_client.py b/src/openai/_base_client.py index b62663b40c..1e5645a297 100644 --- a/src/openai/_base_client.py +++ b/src/openai/_base_client.py @@ -185,7 +185,7 @@ def _iter_file_contents(files: HttpxRequestFiles | None) -> Iterator[object]: if TYPE_CHECKING: from httpx2._config import ( - DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] + DEFAULT_TIMEOUT_CONFIG, ) HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG @@ -265,13 +265,15 @@ class BasePage(GenericModel, Generic[_T]): def has_next_page(self) -> bool: items = self._get_page_items() - if not items: + # Preserve support for custom pages returning non-list iterables. + if not items: # ty: ignore[truthiness-test-of-iterable] return False return self.next_page_info() is not None def next_page_info(self) -> Optional[PageInfo]: ... - def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body] + # Concrete page subclasses supply the items; preserve the existing base-class behavior. + def _get_page_items(self) -> Iterable[_T]: # ty: ignore[empty-body] ... def _params_from_url(self, url: URL) -> httpx2.QueryParams: @@ -333,7 +335,7 @@ def _set_private_attributes( # methods should continue to work as expected as there is an alternative method # to cast a model to a dictionary, model.dict(), which is used internally # by pydantic. - def __iter__(self) -> Iterator[_T]: # type: ignore + def __iter__(self) -> Iterator[_T]: # ty: ignore[invalid-method-override] for page in self.iter_pages(): for item in page._get_page_items(): yield item @@ -388,12 +390,7 @@ def _parser(resp: AsyncPageT) -> AsyncPageT: return await self._client.request(self._page_cls, self._options) async def __aiter__(self) -> AsyncIterator[_T]: - # https://github.com/microsoft/pyright/issues/3464 - page = cast( - AsyncPageT, - await self, # type: ignore - ) - async for item in page: + async for item in await self: yield item @@ -651,7 +648,7 @@ def _build_request( # request based on the truthiness of the "files" argument. # This gets around that issue by generating a dict value that # evaluates to true. - # + # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 if not files: files = cast(HttpxRequestFiles, ForceMultipartDict()) @@ -691,7 +688,7 @@ def _build_request( timeout = normalize_httpx2_timeout(timeout) # TODO: report this error to httpx - return self._client.build_request( # pyright: ignore[reportUnknownMemberType] + return self._client.build_request( headers=request_headers, timeout=timeout, method=options.method, @@ -708,7 +705,7 @@ def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, o items = self.qs.stringify_items( # TODO: type ignore is required as stringify_items is well typed but we can't be # well typed without heavy validation. - data, # type: ignore + data, # ty: ignore[invalid-argument-type] array_format="brackets", ) serialized: dict[str, object] = {} @@ -723,7 +720,7 @@ def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, o # means we're sending data like `array[]=[1, 2, 3]` and we # need to tell httpx that we want to send multiple values with # the same key which is done by using a list or a tuple. - # + # Note: 2d arrays should never result in the same key at both # levels so it's safe to assume that if the value is a list, # it was because we changed it to be a list. @@ -752,7 +749,7 @@ def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalReques return cast_to def _should_stream_response_body(self, request: httpx2.Request) -> bool: - return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return] + return request.headers.get(RAW_RESPONSE_HEADER) == "stream" def _process_response_data( self, @@ -786,7 +783,7 @@ def _process_response_data( # the response or skip validation of any other field. object.__setattr__(validated, "object", data["object"]) return cast(ResponseT, validated) - return cast(ResponseT, validate_type(type_=cast_to, value=data)) + return validate_type(type_=cast_to, value=data) return cast(ResponseT, construct_type(type_=cast_to, value=data)) except pydantic.ValidationError as err: @@ -1020,7 +1017,7 @@ def __init__( if not is_given(timeout): # if the user passed in a custom http client with a non-default # timeout set then we use that timeout. - # + # note: there is an edge case here where the user passes in a client # where they've explicitly set the timeout to match the default timeout # as this check is structural, meaning that we'll think they didn't @@ -1043,8 +1040,7 @@ def __init__( super().__init__( version=version, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), + timeout=timeout, base_url=base_url, max_retries=max_retries, custom_query=custom_query, @@ -1053,8 +1049,7 @@ def __init__( ) self._client = http_client or SyncHttpxClientWrapper( base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), + timeout=timeout, ) def is_closed(self) -> bool: @@ -1335,7 +1330,7 @@ def _process_response( api_response = APIResponse( raw=response, client=self, - cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + cast_to=cast_to, stream=stream, stream_cls=stream_cls, options=options, @@ -1406,8 +1401,7 @@ def get( stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: opts = FinalRequestOptions.construct(method="get", url=path, **options) - # cast is required because mypy complains about returning Any even though - # it understands the type variables + # Preserve the response type through the dynamically selected request overload. return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) @overload @@ -1644,7 +1638,7 @@ def __init__( if not is_given(timeout): # if the user passed in a custom http client with a non-default # timeout set then we use that timeout. - # + # note: there is an edge case here where the user passes in a client # where they've explicitly set the timeout to match the default timeout # as this check is structural, meaning that we'll think they didn't @@ -1668,8 +1662,7 @@ def __init__( super().__init__( version=version, base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), + timeout=timeout, max_retries=max_retries, custom_query=custom_query, custom_headers=custom_headers, @@ -1677,8 +1670,7 @@ def __init__( ) self._client = http_client or AsyncHttpxClientWrapper( base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), + timeout=timeout, ) def is_closed(self) -> bool: @@ -1960,7 +1952,7 @@ async def _process_response( api_response = AsyncAPIResponse( raw=response, client=self, - cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] + cast_to=cast_to, stream=stream, stream_cls=stream_cls, options=options, @@ -2217,8 +2209,8 @@ def make_request_options( options["idempotency_key"] = idempotency_key if is_given(post_parser): - # internal - options["post_parser"] = post_parser # type: ignore + # Internal request hook deliberately omitted from the public RequestOptions type. + options["post_parser"] = post_parser # ty: ignore[invalid-key] if security is not None: options["security"] = security diff --git a/src/openai/_client.py b/src/openai/_client.py index 7dadc8b4ca..525c529fa3 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -80,32 +80,32 @@ if TYPE_CHECKING: from .resources import ( - beta, - chat, - live, - admin, - audio, - evals, - files, - images, - models, - safety, - skills, - videos, - batches, - uploads, - realtime, - webhooks, - decisions, - responses, - containers, - embeddings, - completions, - fine_tuning, - moderations, - conversations, - vector_stores, - content_provenance_checks, + beta as _beta, + chat as _chat, + live as _live, + admin as _admin, + audio as _audio, + evals as _evals, + files as _files, + images as _images, + models as _models, + safety as _safety, + skills as _skills, + videos as _videos, + batches as _batches, + uploads as _uploads, + realtime as _realtime, + webhooks as _webhooks, + decisions as _decisions, + responses as _responses, + containers as _containers, + embeddings as _embeddings, + completions as _completions, + fine_tuning as _fine_tuning, + moderations as _moderations, + conversations as _conversations, + vector_stores as _vector_stores, + content_provenance_checks as _content_provenance_checks, ) from .resources.files import Files, AsyncFiles from .resources.images import Images, AsyncImages @@ -1200,13 +1200,13 @@ def __init__(self, client: OpenAI) -> None: self._client = client @cached_property - def decisions(self) -> decisions.DecisionsWithRawResponse: + def decisions(self) -> _decisions.DecisionsWithRawResponse: from .resources.decisions import DecisionsWithRawResponse return DecisionsWithRawResponse(self._client.decisions) @cached_property - def completions(self) -> completions.CompletionsWithRawResponse: + def completions(self) -> _completions.CompletionsWithRawResponse: """ Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. """ @@ -1215,13 +1215,13 @@ def completions(self) -> completions.CompletionsWithRawResponse: return CompletionsWithRawResponse(self._client.completions) @cached_property - def chat(self) -> chat.ChatWithRawResponse: + def chat(self) -> _chat.ChatWithRawResponse: from .resources.chat import ChatWithRawResponse return ChatWithRawResponse(self._client.chat) @cached_property - def embeddings(self) -> embeddings.EmbeddingsWithRawResponse: + def embeddings(self) -> _embeddings.EmbeddingsWithRawResponse: """ Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. """ @@ -1230,7 +1230,7 @@ def embeddings(self) -> embeddings.EmbeddingsWithRawResponse: return EmbeddingsWithRawResponse(self._client.embeddings) @cached_property - def files(self) -> files.FilesWithRawResponse: + def files(self) -> _files.FilesWithRawResponse: """ Files are used to upload documents that can be used with features like Assistants and Fine-tuning. """ @@ -1239,26 +1239,26 @@ def files(self) -> files.FilesWithRawResponse: return FilesWithRawResponse(self._client.files) @cached_property - def images(self) -> images.ImagesWithRawResponse: + def images(self) -> _images.ImagesWithRawResponse: """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import ImagesWithRawResponse return ImagesWithRawResponse(self._client.images) @cached_property - def content_provenance_checks(self) -> content_provenance_checks.ContentProvenanceChecksWithRawResponse: + def content_provenance_checks(self) -> _content_provenance_checks.ContentProvenanceChecksWithRawResponse: from .resources.content_provenance_checks import ContentProvenanceChecksWithRawResponse return ContentProvenanceChecksWithRawResponse(self._client.content_provenance_checks) @cached_property - def audio(self) -> audio.AudioWithRawResponse: + def audio(self) -> _audio.AudioWithRawResponse: from .resources.audio import AudioWithRawResponse return AudioWithRawResponse(self._client.audio) @cached_property - def moderations(self) -> moderations.ModerationsWithRawResponse: + def moderations(self) -> _moderations.ModerationsWithRawResponse: """ Given text and/or image inputs, classifies if those inputs are potentially harmful. """ @@ -1267,109 +1267,109 @@ def moderations(self) -> moderations.ModerationsWithRawResponse: return ModerationsWithRawResponse(self._client.moderations) @cached_property - def models(self) -> models.ModelsWithRawResponse: + def models(self) -> _models.ModelsWithRawResponse: """List and describe the various models available in the API.""" from .resources.models import ModelsWithRawResponse return ModelsWithRawResponse(self._client.models) @cached_property - def fine_tuning(self) -> fine_tuning.FineTuningWithRawResponse: + def fine_tuning(self) -> _fine_tuning.FineTuningWithRawResponse: from .resources.fine_tuning import FineTuningWithRawResponse return FineTuningWithRawResponse(self._client.fine_tuning) @cached_property - def vector_stores(self) -> vector_stores.VectorStoresWithRawResponse: + def vector_stores(self) -> _vector_stores.VectorStoresWithRawResponse: from .resources.vector_stores import VectorStoresWithRawResponse return VectorStoresWithRawResponse(self._client.vector_stores) @cached_property - def safety(self) -> safety.SafetyWithRawResponse: + def safety(self) -> _safety.SafetyWithRawResponse: from .resources.safety import SafetyWithRawResponse return SafetyWithRawResponse(self._client.safety) @cached_property - def webhooks(self) -> webhooks.WebhooksWithRawResponse: + def webhooks(self) -> _webhooks.WebhooksWithRawResponse: from .resources.webhooks import WebhooksWithRawResponse return WebhooksWithRawResponse(self._client.webhooks) @cached_property - def beta(self) -> beta.BetaWithRawResponse: + def beta(self) -> _beta.BetaWithRawResponse: from .resources.beta import BetaWithRawResponse return BetaWithRawResponse(self._client.beta) @cached_property - def batches(self) -> batches.BatchesWithRawResponse: + def batches(self) -> _batches.BatchesWithRawResponse: """Create large batches of API requests to run asynchronously.""" from .resources.batches import BatchesWithRawResponse return BatchesWithRawResponse(self._client.batches) @cached_property - def uploads(self) -> uploads.UploadsWithRawResponse: + def uploads(self) -> _uploads.UploadsWithRawResponse: """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import UploadsWithRawResponse return UploadsWithRawResponse(self._client.uploads) @cached_property - def admin(self) -> admin.AdminWithRawResponse: + def admin(self) -> _admin.AdminWithRawResponse: from .resources.admin import AdminWithRawResponse return AdminWithRawResponse(self._client.admin) @cached_property - def responses(self) -> responses.ResponsesWithRawResponse: + def responses(self) -> _responses.ResponsesWithRawResponse: """Create and manage model responses.""" from .resources.responses import ResponsesWithRawResponse return ResponsesWithRawResponse(self._client.responses) @cached_property - def live(self) -> live.LiveWithRawResponse: + def live(self) -> _live.LiveWithRawResponse: from .resources.live import LiveWithRawResponse return LiveWithRawResponse(self._client.live) @cached_property - def realtime(self) -> realtime.RealtimeWithRawResponse: + def realtime(self) -> _realtime.RealtimeWithRawResponse: from .resources.realtime import RealtimeWithRawResponse return RealtimeWithRawResponse(self._client.realtime) @cached_property - def conversations(self) -> conversations.ConversationsWithRawResponse: + def conversations(self) -> _conversations.ConversationsWithRawResponse: """Manage conversations and conversation items.""" from .resources.conversations import ConversationsWithRawResponse return ConversationsWithRawResponse(self._client.conversations) @cached_property - def evals(self) -> evals.EvalsWithRawResponse: + def evals(self) -> _evals.EvalsWithRawResponse: """Manage and run evals in the OpenAI platform.""" from .resources.evals import EvalsWithRawResponse return EvalsWithRawResponse(self._client.evals) @cached_property - def containers(self) -> containers.ContainersWithRawResponse: + def containers(self) -> _containers.ContainersWithRawResponse: from .resources.containers import ContainersWithRawResponse return ContainersWithRawResponse(self._client.containers) @cached_property - def skills(self) -> skills.SkillsWithRawResponse: + def skills(self) -> _skills.SkillsWithRawResponse: from .resources.skills import SkillsWithRawResponse return SkillsWithRawResponse(self._client.skills) @cached_property - def videos(self) -> videos.VideosWithRawResponse: + def videos(self) -> _videos.VideosWithRawResponse: from .resources.videos import VideosWithRawResponse return VideosWithRawResponse(self._client.videos) @@ -1382,13 +1382,13 @@ def __init__(self, client: AsyncOpenAI) -> None: self._client = client @cached_property - def decisions(self) -> decisions.AsyncDecisionsWithRawResponse: + def decisions(self) -> _decisions.AsyncDecisionsWithRawResponse: from .resources.decisions import AsyncDecisionsWithRawResponse return AsyncDecisionsWithRawResponse(self._client.decisions) @cached_property - def completions(self) -> completions.AsyncCompletionsWithRawResponse: + def completions(self) -> _completions.AsyncCompletionsWithRawResponse: """ Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. """ @@ -1397,13 +1397,13 @@ def completions(self) -> completions.AsyncCompletionsWithRawResponse: return AsyncCompletionsWithRawResponse(self._client.completions) @cached_property - def chat(self) -> chat.AsyncChatWithRawResponse: + def chat(self) -> _chat.AsyncChatWithRawResponse: from .resources.chat import AsyncChatWithRawResponse return AsyncChatWithRawResponse(self._client.chat) @cached_property - def embeddings(self) -> embeddings.AsyncEmbeddingsWithRawResponse: + def embeddings(self) -> _embeddings.AsyncEmbeddingsWithRawResponse: """ Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. """ @@ -1412,7 +1412,7 @@ def embeddings(self) -> embeddings.AsyncEmbeddingsWithRawResponse: return AsyncEmbeddingsWithRawResponse(self._client.embeddings) @cached_property - def files(self) -> files.AsyncFilesWithRawResponse: + def files(self) -> _files.AsyncFilesWithRawResponse: """ Files are used to upload documents that can be used with features like Assistants and Fine-tuning. """ @@ -1421,26 +1421,26 @@ def files(self) -> files.AsyncFilesWithRawResponse: return AsyncFilesWithRawResponse(self._client.files) @cached_property - def images(self) -> images.AsyncImagesWithRawResponse: + def images(self) -> _images.AsyncImagesWithRawResponse: """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import AsyncImagesWithRawResponse return AsyncImagesWithRawResponse(self._client.images) @cached_property - def content_provenance_checks(self) -> content_provenance_checks.AsyncContentProvenanceChecksWithRawResponse: + def content_provenance_checks(self) -> _content_provenance_checks.AsyncContentProvenanceChecksWithRawResponse: from .resources.content_provenance_checks import AsyncContentProvenanceChecksWithRawResponse return AsyncContentProvenanceChecksWithRawResponse(self._client.content_provenance_checks) @cached_property - def audio(self) -> audio.AsyncAudioWithRawResponse: + def audio(self) -> _audio.AsyncAudioWithRawResponse: from .resources.audio import AsyncAudioWithRawResponse return AsyncAudioWithRawResponse(self._client.audio) @cached_property - def moderations(self) -> moderations.AsyncModerationsWithRawResponse: + def moderations(self) -> _moderations.AsyncModerationsWithRawResponse: """ Given text and/or image inputs, classifies if those inputs are potentially harmful. """ @@ -1449,109 +1449,109 @@ def moderations(self) -> moderations.AsyncModerationsWithRawResponse: return AsyncModerationsWithRawResponse(self._client.moderations) @cached_property - def models(self) -> models.AsyncModelsWithRawResponse: + def models(self) -> _models.AsyncModelsWithRawResponse: """List and describe the various models available in the API.""" from .resources.models import AsyncModelsWithRawResponse return AsyncModelsWithRawResponse(self._client.models) @cached_property - def fine_tuning(self) -> fine_tuning.AsyncFineTuningWithRawResponse: + def fine_tuning(self) -> _fine_tuning.AsyncFineTuningWithRawResponse: from .resources.fine_tuning import AsyncFineTuningWithRawResponse return AsyncFineTuningWithRawResponse(self._client.fine_tuning) @cached_property - def vector_stores(self) -> vector_stores.AsyncVectorStoresWithRawResponse: + def vector_stores(self) -> _vector_stores.AsyncVectorStoresWithRawResponse: from .resources.vector_stores import AsyncVectorStoresWithRawResponse return AsyncVectorStoresWithRawResponse(self._client.vector_stores) @cached_property - def safety(self) -> safety.AsyncSafetyWithRawResponse: + def safety(self) -> _safety.AsyncSafetyWithRawResponse: from .resources.safety import AsyncSafetyWithRawResponse return AsyncSafetyWithRawResponse(self._client.safety) @cached_property - def webhooks(self) -> webhooks.AsyncWebhooksWithRawResponse: + def webhooks(self) -> _webhooks.AsyncWebhooksWithRawResponse: from .resources.webhooks import AsyncWebhooksWithRawResponse return AsyncWebhooksWithRawResponse(self._client.webhooks) @cached_property - def beta(self) -> beta.AsyncBetaWithRawResponse: + def beta(self) -> _beta.AsyncBetaWithRawResponse: from .resources.beta import AsyncBetaWithRawResponse return AsyncBetaWithRawResponse(self._client.beta) @cached_property - def batches(self) -> batches.AsyncBatchesWithRawResponse: + def batches(self) -> _batches.AsyncBatchesWithRawResponse: """Create large batches of API requests to run asynchronously.""" from .resources.batches import AsyncBatchesWithRawResponse return AsyncBatchesWithRawResponse(self._client.batches) @cached_property - def uploads(self) -> uploads.AsyncUploadsWithRawResponse: + def uploads(self) -> _uploads.AsyncUploadsWithRawResponse: """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import AsyncUploadsWithRawResponse return AsyncUploadsWithRawResponse(self._client.uploads) @cached_property - def admin(self) -> admin.AsyncAdminWithRawResponse: + def admin(self) -> _admin.AsyncAdminWithRawResponse: from .resources.admin import AsyncAdminWithRawResponse return AsyncAdminWithRawResponse(self._client.admin) @cached_property - def responses(self) -> responses.AsyncResponsesWithRawResponse: + def responses(self) -> _responses.AsyncResponsesWithRawResponse: """Create and manage model responses.""" from .resources.responses import AsyncResponsesWithRawResponse return AsyncResponsesWithRawResponse(self._client.responses) @cached_property - def live(self) -> live.AsyncLiveWithRawResponse: + def live(self) -> _live.AsyncLiveWithRawResponse: from .resources.live import AsyncLiveWithRawResponse return AsyncLiveWithRawResponse(self._client.live) @cached_property - def realtime(self) -> realtime.AsyncRealtimeWithRawResponse: + def realtime(self) -> _realtime.AsyncRealtimeWithRawResponse: from .resources.realtime import AsyncRealtimeWithRawResponse return AsyncRealtimeWithRawResponse(self._client.realtime) @cached_property - def conversations(self) -> conversations.AsyncConversationsWithRawResponse: + def conversations(self) -> _conversations.AsyncConversationsWithRawResponse: """Manage conversations and conversation items.""" from .resources.conversations import AsyncConversationsWithRawResponse return AsyncConversationsWithRawResponse(self._client.conversations) @cached_property - def evals(self) -> evals.AsyncEvalsWithRawResponse: + def evals(self) -> _evals.AsyncEvalsWithRawResponse: """Manage and run evals in the OpenAI platform.""" from .resources.evals import AsyncEvalsWithRawResponse return AsyncEvalsWithRawResponse(self._client.evals) @cached_property - def containers(self) -> containers.AsyncContainersWithRawResponse: + def containers(self) -> _containers.AsyncContainersWithRawResponse: from .resources.containers import AsyncContainersWithRawResponse return AsyncContainersWithRawResponse(self._client.containers) @cached_property - def skills(self) -> skills.AsyncSkillsWithRawResponse: + def skills(self) -> _skills.AsyncSkillsWithRawResponse: from .resources.skills import AsyncSkillsWithRawResponse return AsyncSkillsWithRawResponse(self._client.skills) @cached_property - def videos(self) -> videos.AsyncVideosWithRawResponse: + def videos(self) -> _videos.AsyncVideosWithRawResponse: from .resources.videos import AsyncVideosWithRawResponse return AsyncVideosWithRawResponse(self._client.videos) @@ -1564,13 +1564,13 @@ def __init__(self, client: OpenAI) -> None: self._client = client @cached_property - def decisions(self) -> decisions.DecisionsWithStreamingResponse: + def decisions(self) -> _decisions.DecisionsWithStreamingResponse: from .resources.decisions import DecisionsWithStreamingResponse return DecisionsWithStreamingResponse(self._client.decisions) @cached_property - def completions(self) -> completions.CompletionsWithStreamingResponse: + def completions(self) -> _completions.CompletionsWithStreamingResponse: """ Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. """ @@ -1579,13 +1579,13 @@ def completions(self) -> completions.CompletionsWithStreamingResponse: return CompletionsWithStreamingResponse(self._client.completions) @cached_property - def chat(self) -> chat.ChatWithStreamingResponse: + def chat(self) -> _chat.ChatWithStreamingResponse: from .resources.chat import ChatWithStreamingResponse return ChatWithStreamingResponse(self._client.chat) @cached_property - def embeddings(self) -> embeddings.EmbeddingsWithStreamingResponse: + def embeddings(self) -> _embeddings.EmbeddingsWithStreamingResponse: """ Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. """ @@ -1594,7 +1594,7 @@ def embeddings(self) -> embeddings.EmbeddingsWithStreamingResponse: return EmbeddingsWithStreamingResponse(self._client.embeddings) @cached_property - def files(self) -> files.FilesWithStreamingResponse: + def files(self) -> _files.FilesWithStreamingResponse: """ Files are used to upload documents that can be used with features like Assistants and Fine-tuning. """ @@ -1603,26 +1603,26 @@ def files(self) -> files.FilesWithStreamingResponse: return FilesWithStreamingResponse(self._client.files) @cached_property - def images(self) -> images.ImagesWithStreamingResponse: + def images(self) -> _images.ImagesWithStreamingResponse: """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import ImagesWithStreamingResponse return ImagesWithStreamingResponse(self._client.images) @cached_property - def content_provenance_checks(self) -> content_provenance_checks.ContentProvenanceChecksWithStreamingResponse: + def content_provenance_checks(self) -> _content_provenance_checks.ContentProvenanceChecksWithStreamingResponse: from .resources.content_provenance_checks import ContentProvenanceChecksWithStreamingResponse return ContentProvenanceChecksWithStreamingResponse(self._client.content_provenance_checks) @cached_property - def audio(self) -> audio.AudioWithStreamingResponse: + def audio(self) -> _audio.AudioWithStreamingResponse: from .resources.audio import AudioWithStreamingResponse return AudioWithStreamingResponse(self._client.audio) @cached_property - def moderations(self) -> moderations.ModerationsWithStreamingResponse: + def moderations(self) -> _moderations.ModerationsWithStreamingResponse: """ Given text and/or image inputs, classifies if those inputs are potentially harmful. """ @@ -1631,109 +1631,109 @@ def moderations(self) -> moderations.ModerationsWithStreamingResponse: return ModerationsWithStreamingResponse(self._client.moderations) @cached_property - def models(self) -> models.ModelsWithStreamingResponse: + def models(self) -> _models.ModelsWithStreamingResponse: """List and describe the various models available in the API.""" from .resources.models import ModelsWithStreamingResponse return ModelsWithStreamingResponse(self._client.models) @cached_property - def fine_tuning(self) -> fine_tuning.FineTuningWithStreamingResponse: + def fine_tuning(self) -> _fine_tuning.FineTuningWithStreamingResponse: from .resources.fine_tuning import FineTuningWithStreamingResponse return FineTuningWithStreamingResponse(self._client.fine_tuning) @cached_property - def vector_stores(self) -> vector_stores.VectorStoresWithStreamingResponse: + def vector_stores(self) -> _vector_stores.VectorStoresWithStreamingResponse: from .resources.vector_stores import VectorStoresWithStreamingResponse return VectorStoresWithStreamingResponse(self._client.vector_stores) @cached_property - def safety(self) -> safety.SafetyWithStreamingResponse: + def safety(self) -> _safety.SafetyWithStreamingResponse: from .resources.safety import SafetyWithStreamingResponse return SafetyWithStreamingResponse(self._client.safety) @cached_property - def webhooks(self) -> webhooks.WebhooksWithStreamingResponse: + def webhooks(self) -> _webhooks.WebhooksWithStreamingResponse: from .resources.webhooks import WebhooksWithStreamingResponse return WebhooksWithStreamingResponse(self._client.webhooks) @cached_property - def beta(self) -> beta.BetaWithStreamingResponse: + def beta(self) -> _beta.BetaWithStreamingResponse: from .resources.beta import BetaWithStreamingResponse return BetaWithStreamingResponse(self._client.beta) @cached_property - def batches(self) -> batches.BatchesWithStreamingResponse: + def batches(self) -> _batches.BatchesWithStreamingResponse: """Create large batches of API requests to run asynchronously.""" from .resources.batches import BatchesWithStreamingResponse return BatchesWithStreamingResponse(self._client.batches) @cached_property - def uploads(self) -> uploads.UploadsWithStreamingResponse: + def uploads(self) -> _uploads.UploadsWithStreamingResponse: """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import UploadsWithStreamingResponse return UploadsWithStreamingResponse(self._client.uploads) @cached_property - def admin(self) -> admin.AdminWithStreamingResponse: + def admin(self) -> _admin.AdminWithStreamingResponse: from .resources.admin import AdminWithStreamingResponse return AdminWithStreamingResponse(self._client.admin) @cached_property - def responses(self) -> responses.ResponsesWithStreamingResponse: + def responses(self) -> _responses.ResponsesWithStreamingResponse: """Create and manage model responses.""" from .resources.responses import ResponsesWithStreamingResponse return ResponsesWithStreamingResponse(self._client.responses) @cached_property - def live(self) -> live.LiveWithStreamingResponse: + def live(self) -> _live.LiveWithStreamingResponse: from .resources.live import LiveWithStreamingResponse return LiveWithStreamingResponse(self._client.live) @cached_property - def realtime(self) -> realtime.RealtimeWithStreamingResponse: + def realtime(self) -> _realtime.RealtimeWithStreamingResponse: from .resources.realtime import RealtimeWithStreamingResponse return RealtimeWithStreamingResponse(self._client.realtime) @cached_property - def conversations(self) -> conversations.ConversationsWithStreamingResponse: + def conversations(self) -> _conversations.ConversationsWithStreamingResponse: """Manage conversations and conversation items.""" from .resources.conversations import ConversationsWithStreamingResponse return ConversationsWithStreamingResponse(self._client.conversations) @cached_property - def evals(self) -> evals.EvalsWithStreamingResponse: + def evals(self) -> _evals.EvalsWithStreamingResponse: """Manage and run evals in the OpenAI platform.""" from .resources.evals import EvalsWithStreamingResponse return EvalsWithStreamingResponse(self._client.evals) @cached_property - def containers(self) -> containers.ContainersWithStreamingResponse: + def containers(self) -> _containers.ContainersWithStreamingResponse: from .resources.containers import ContainersWithStreamingResponse return ContainersWithStreamingResponse(self._client.containers) @cached_property - def skills(self) -> skills.SkillsWithStreamingResponse: + def skills(self) -> _skills.SkillsWithStreamingResponse: from .resources.skills import SkillsWithStreamingResponse return SkillsWithStreamingResponse(self._client.skills) @cached_property - def videos(self) -> videos.VideosWithStreamingResponse: + def videos(self) -> _videos.VideosWithStreamingResponse: from .resources.videos import VideosWithStreamingResponse return VideosWithStreamingResponse(self._client.videos) @@ -1746,13 +1746,13 @@ def __init__(self, client: AsyncOpenAI) -> None: self._client = client @cached_property - def decisions(self) -> decisions.AsyncDecisionsWithStreamingResponse: + def decisions(self) -> _decisions.AsyncDecisionsWithStreamingResponse: from .resources.decisions import AsyncDecisionsWithStreamingResponse return AsyncDecisionsWithStreamingResponse(self._client.decisions) @cached_property - def completions(self) -> completions.AsyncCompletionsWithStreamingResponse: + def completions(self) -> _completions.AsyncCompletionsWithStreamingResponse: """ Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. """ @@ -1761,13 +1761,13 @@ def completions(self) -> completions.AsyncCompletionsWithStreamingResponse: return AsyncCompletionsWithStreamingResponse(self._client.completions) @cached_property - def chat(self) -> chat.AsyncChatWithStreamingResponse: + def chat(self) -> _chat.AsyncChatWithStreamingResponse: from .resources.chat import AsyncChatWithStreamingResponse return AsyncChatWithStreamingResponse(self._client.chat) @cached_property - def embeddings(self) -> embeddings.AsyncEmbeddingsWithStreamingResponse: + def embeddings(self) -> _embeddings.AsyncEmbeddingsWithStreamingResponse: """ Get a vector representation of a given input that can be easily consumed by machine learning models and algorithms. """ @@ -1776,7 +1776,7 @@ def embeddings(self) -> embeddings.AsyncEmbeddingsWithStreamingResponse: return AsyncEmbeddingsWithStreamingResponse(self._client.embeddings) @cached_property - def files(self) -> files.AsyncFilesWithStreamingResponse: + def files(self) -> _files.AsyncFilesWithStreamingResponse: """ Files are used to upload documents that can be used with features like Assistants and Fine-tuning. """ @@ -1785,26 +1785,26 @@ def files(self) -> files.AsyncFilesWithStreamingResponse: return AsyncFilesWithStreamingResponse(self._client.files) @cached_property - def images(self) -> images.AsyncImagesWithStreamingResponse: + def images(self) -> _images.AsyncImagesWithStreamingResponse: """Given a prompt and/or an input image, the model will generate a new image.""" from .resources.images import AsyncImagesWithStreamingResponse return AsyncImagesWithStreamingResponse(self._client.images) @cached_property - def content_provenance_checks(self) -> content_provenance_checks.AsyncContentProvenanceChecksWithStreamingResponse: + def content_provenance_checks(self) -> _content_provenance_checks.AsyncContentProvenanceChecksWithStreamingResponse: from .resources.content_provenance_checks import AsyncContentProvenanceChecksWithStreamingResponse return AsyncContentProvenanceChecksWithStreamingResponse(self._client.content_provenance_checks) @cached_property - def audio(self) -> audio.AsyncAudioWithStreamingResponse: + def audio(self) -> _audio.AsyncAudioWithStreamingResponse: from .resources.audio import AsyncAudioWithStreamingResponse return AsyncAudioWithStreamingResponse(self._client.audio) @cached_property - def moderations(self) -> moderations.AsyncModerationsWithStreamingResponse: + def moderations(self) -> _moderations.AsyncModerationsWithStreamingResponse: """ Given text and/or image inputs, classifies if those inputs are potentially harmful. """ @@ -1813,109 +1813,109 @@ def moderations(self) -> moderations.AsyncModerationsWithStreamingResponse: return AsyncModerationsWithStreamingResponse(self._client.moderations) @cached_property - def models(self) -> models.AsyncModelsWithStreamingResponse: + def models(self) -> _models.AsyncModelsWithStreamingResponse: """List and describe the various models available in the API.""" from .resources.models import AsyncModelsWithStreamingResponse return AsyncModelsWithStreamingResponse(self._client.models) @cached_property - def fine_tuning(self) -> fine_tuning.AsyncFineTuningWithStreamingResponse: + def fine_tuning(self) -> _fine_tuning.AsyncFineTuningWithStreamingResponse: from .resources.fine_tuning import AsyncFineTuningWithStreamingResponse return AsyncFineTuningWithStreamingResponse(self._client.fine_tuning) @cached_property - def vector_stores(self) -> vector_stores.AsyncVectorStoresWithStreamingResponse: + def vector_stores(self) -> _vector_stores.AsyncVectorStoresWithStreamingResponse: from .resources.vector_stores import AsyncVectorStoresWithStreamingResponse return AsyncVectorStoresWithStreamingResponse(self._client.vector_stores) @cached_property - def safety(self) -> safety.AsyncSafetyWithStreamingResponse: + def safety(self) -> _safety.AsyncSafetyWithStreamingResponse: from .resources.safety import AsyncSafetyWithStreamingResponse return AsyncSafetyWithStreamingResponse(self._client.safety) @cached_property - def webhooks(self) -> webhooks.AsyncWebhooksWithStreamingResponse: + def webhooks(self) -> _webhooks.AsyncWebhooksWithStreamingResponse: from .resources.webhooks import AsyncWebhooksWithStreamingResponse return AsyncWebhooksWithStreamingResponse(self._client.webhooks) @cached_property - def beta(self) -> beta.AsyncBetaWithStreamingResponse: + def beta(self) -> _beta.AsyncBetaWithStreamingResponse: from .resources.beta import AsyncBetaWithStreamingResponse return AsyncBetaWithStreamingResponse(self._client.beta) @cached_property - def batches(self) -> batches.AsyncBatchesWithStreamingResponse: + def batches(self) -> _batches.AsyncBatchesWithStreamingResponse: """Create large batches of API requests to run asynchronously.""" from .resources.batches import AsyncBatchesWithStreamingResponse return AsyncBatchesWithStreamingResponse(self._client.batches) @cached_property - def uploads(self) -> uploads.AsyncUploadsWithStreamingResponse: + def uploads(self) -> _uploads.AsyncUploadsWithStreamingResponse: """Use Uploads to upload large files in multiple parts.""" from .resources.uploads import AsyncUploadsWithStreamingResponse return AsyncUploadsWithStreamingResponse(self._client.uploads) @cached_property - def admin(self) -> admin.AsyncAdminWithStreamingResponse: + def admin(self) -> _admin.AsyncAdminWithStreamingResponse: from .resources.admin import AsyncAdminWithStreamingResponse return AsyncAdminWithStreamingResponse(self._client.admin) @cached_property - def responses(self) -> responses.AsyncResponsesWithStreamingResponse: + def responses(self) -> _responses.AsyncResponsesWithStreamingResponse: """Create and manage model responses.""" from .resources.responses import AsyncResponsesWithStreamingResponse return AsyncResponsesWithStreamingResponse(self._client.responses) @cached_property - def live(self) -> live.AsyncLiveWithStreamingResponse: + def live(self) -> _live.AsyncLiveWithStreamingResponse: from .resources.live import AsyncLiveWithStreamingResponse return AsyncLiveWithStreamingResponse(self._client.live) @cached_property - def realtime(self) -> realtime.AsyncRealtimeWithStreamingResponse: + def realtime(self) -> _realtime.AsyncRealtimeWithStreamingResponse: from .resources.realtime import AsyncRealtimeWithStreamingResponse return AsyncRealtimeWithStreamingResponse(self._client.realtime) @cached_property - def conversations(self) -> conversations.AsyncConversationsWithStreamingResponse: + def conversations(self) -> _conversations.AsyncConversationsWithStreamingResponse: """Manage conversations and conversation items.""" from .resources.conversations import AsyncConversationsWithStreamingResponse return AsyncConversationsWithStreamingResponse(self._client.conversations) @cached_property - def evals(self) -> evals.AsyncEvalsWithStreamingResponse: + def evals(self) -> _evals.AsyncEvalsWithStreamingResponse: """Manage and run evals in the OpenAI platform.""" from .resources.evals import AsyncEvalsWithStreamingResponse return AsyncEvalsWithStreamingResponse(self._client.evals) @cached_property - def containers(self) -> containers.AsyncContainersWithStreamingResponse: + def containers(self) -> _containers.AsyncContainersWithStreamingResponse: from .resources.containers import AsyncContainersWithStreamingResponse return AsyncContainersWithStreamingResponse(self._client.containers) @cached_property - def skills(self) -> skills.AsyncSkillsWithStreamingResponse: + def skills(self) -> _skills.AsyncSkillsWithStreamingResponse: from .resources.skills import AsyncSkillsWithStreamingResponse return AsyncSkillsWithStreamingResponse(self._client.skills) @cached_property - def videos(self) -> videos.AsyncVideosWithStreamingResponse: + def videos(self) -> _videos.AsyncVideosWithStreamingResponse: from .resources.videos import AsyncVideosWithStreamingResponse return AsyncVideosWithStreamingResponse(self._client.videos) diff --git a/src/openai/_compat.py b/src/openai/_compat.py index 340c91a6d0..9c5c692d30 100644 --- a/src/openai/_compat.py +++ b/src/openai/_compat.py @@ -14,9 +14,6 @@ # --------------- Pydantic v2, v3 compatibility --------------- -# Pyright incorrectly reports some of our functions as overriding a method when they don't -# pyright: reportIncompatibleMethodOverride=false - PYDANTIC_V1 = pydantic.VERSION.startswith("1.") if TYPE_CHECKING: @@ -79,14 +76,14 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 # renamed methods / properties def parse_obj(model: type[_ModelT], value: object) -> _ModelT: if PYDANTIC_V1: - return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + return model.parse_obj(value) else: return model.model_validate(value) def field_is_required(field: FieldInfo) -> bool: if PYDANTIC_V1: - return field.required # type: ignore + return field.required return field.is_required() @@ -103,31 +100,31 @@ def field_get_default(field: FieldInfo) -> Any: def field_outer_type(field: FieldInfo) -> Any: if PYDANTIC_V1: - return field.outer_type_ # type: ignore + return field.outer_type_ return field.annotation def get_model_config(model: type[pydantic.BaseModel]) -> Any: if PYDANTIC_V1: - return model.__config__ # type: ignore + return model.__config__ return model.model_config def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: if PYDANTIC_V1: - return model.__fields__ # type: ignore + return model.__fields__ return model.model_fields def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: if PYDANTIC_V1: - return model.copy(deep=deep) # type: ignore + return model.copy(deep=deep) return model.model_copy(deep=deep) def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: if PYDANTIC_V1: - return model.json(indent=indent) # type: ignore + return model.json(indent=indent) return model.model_dump_json(indent=indent) @@ -160,7 +157,7 @@ def model_dump( ) return cast( "dict[str, Any]", - model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + model.dict( exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) ), ) @@ -168,19 +165,19 @@ def model_dump( def model_parse(model: type[_ModelT], data: Any) -> _ModelT: if PYDANTIC_V1: - return model.parse_obj(data) # pyright: ignore[reportDeprecated] + return model.parse_obj(data) return model.model_validate(data) def model_parse_json(model: type[_ModelT], data: str | bytes) -> _ModelT: if PYDANTIC_V1: - return model.parse_raw(data) # pyright: ignore[reportDeprecated] + return model.parse_raw(data) return model.model_validate_json(data) def model_json_schema(model: type[_ModelT]) -> dict[str, Any]: if PYDANTIC_V1: - return model.schema() # pyright: ignore[reportDeprecated] + return model.schema() return model.model_json_schema() @@ -208,7 +205,7 @@ class GenericModel(pydantic.BaseModel): ... # we define a separate type (copied from typeshed) # that represents that `cached_property` is `set`able # at runtime, which differs from `@property`. - # + # this is a separate type as editors likely special case # `@property` and we don't want to cause issues just to have # more helpful internal types. diff --git a/src/openai/_exceptions.py b/src/openai/_exceptions.py index 9ced39e64f..6c3cad5c8e 100644 --- a/src/openai/_exceptions.py +++ b/src/openai/_exceptions.py @@ -114,11 +114,11 @@ def __init__(self, request: httpx2.Request) -> None: class BadRequestError(APIStatusError): - status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride] + status_code: Literal[400] = 400 class AuthenticationError(APIStatusError): - status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride] + status_code: Literal[401] = 401 class OAuthError(AuthenticationError): @@ -139,23 +139,23 @@ def __init__(self, *, response: httpx2.Response, body: object | None) -> None: class PermissionDeniedError(APIStatusError): - status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride] + status_code: Literal[403] = 403 class NotFoundError(APIStatusError): - status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride] + status_code: Literal[404] = 404 class ConflictError(APIStatusError): - status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride] + status_code: Literal[409] = 409 class UnprocessableEntityError(APIStatusError): - status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride] + status_code: Literal[422] = 422 class RateLimitError(APIStatusError): - status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride] + status_code: Literal[429] = 429 class InternalServerError(APIStatusError): diff --git a/src/openai/_extras/numpy_proxy.py b/src/openai/_extras/numpy_proxy.py index 2b0669576e..6e32c3ed94 100644 --- a/src/openai/_extras/numpy_proxy.py +++ b/src/openai/_extras/numpy_proxy.py @@ -30,7 +30,7 @@ def __load__(self) -> Any: def has_numpy() -> bool: try: - import numpy # noqa: F401 # pyright: ignore[reportUnusedImport] + import numpy # noqa: F401 except ImportError: return False diff --git a/src/openai/_extras/sounddevice_proxy.py b/src/openai/_extras/sounddevice_proxy.py index 482d4c6874..a1e0d3e086 100644 --- a/src/openai/_extras/sounddevice_proxy.py +++ b/src/openai/_extras/sounddevice_proxy.py @@ -7,7 +7,7 @@ from ._common import MissingDependencyError, format_instructions if TYPE_CHECKING: - import sounddevice as sounddevice # type: ignore + import sounddevice as sounddevice SOUNDDEVICE_INSTRUCTIONS = format_instructions(library="sounddevice", extra="voice_helpers") @@ -17,7 +17,7 @@ class SounddeviceProxy(LazyProxy[Any]): @override def __load__(self) -> Any: try: - import sounddevice # type: ignore + import sounddevice except ImportError as err: raise MissingDependencyError(SOUNDDEVICE_INSTRUCTIONS) from err diff --git a/src/openai/_files.py b/src/openai/_files.py index 76f71238ff..64e9f9410c 100644 --- a/src/openai/_files.py +++ b/src/openai/_files.py @@ -154,7 +154,7 @@ def _deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]], index: int) - # if no path continues through this mapping, it won't be mutated and copying it is redundant if not key_to_paths: - return item + return cast(_T, item) result = dict(item) for key, subpaths in key_to_paths.items(): diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index bfbdcb1ab6..023be82862 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -90,7 +90,7 @@ def __init__( @property def request_id(self) -> str | None: - return self.http_response.headers.get("x-request-id") # type: ignore[no-any-return] + return self.http_response.headers.get("x-request-id") @overload def parse(self, *, to: type[_T]) -> _T: ... @@ -133,7 +133,7 @@ class MyModel(BaseModel): cache_key = to if to is not None else self._cast_to cached = self._parsed_by_type.get(cache_key) if cached is not None: - return cached # type: ignore[no-any-return] + return cached parsed = self._parse(to=to) if is_given(self._options.post_parser): @@ -200,7 +200,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # unwrap `TypeAlias('Name', T)` -> `T` if is_type_alias_type(cast_to): - cast_to = cast_to.__value__ # type: ignore[unreachable] + cast_to = cast_to.__value__ # unwrap `Annotated[T, ...]` -> `T` if cast_to and is_annotated_type(cast_to): @@ -268,15 +268,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: return cast(R, response.text.strip().lower() == "true") if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent): - return cast(R, cast_to(response)) # type: ignore + return cast(R, cast_to(response)) if origin == LegacyAPIResponse: raise RuntimeError("Unexpected state - cast_to is `APIResponse`") response_types = http_response_types() - if inspect.isclass( - origin # pyright: ignore[reportUnknownArgumentType] - ) and issubclass(origin, response_types): + if inspect.isclass(origin) and issubclass(origin, response_types): # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response # and pass that class to our request functions. We cannot change the variance to be either # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct @@ -286,13 +284,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: raise ValueError("Subclasses of HTTP response classes cannot be passed to `cast_to`") return cast(R, response) - if ( - inspect.isclass( - origin # pyright: ignore[reportUnknownArgumentType] - ) - and not issubclass(origin, BaseModel) - and issubclass(origin, pydantic.BaseModel) - ): + if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel): raise TypeError("Pydantic models must subclass our base model type, e.g. `from openai import BaseModel`") if ( @@ -316,9 +308,10 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: except Exception as exc: log.debug("Could not read JSON from response data due to %s", type(exc).__name__) else: - return self._client._process_response_data( + # cast_to is validated above and preserves the response generic through dynamic parsing. + return self._client._process_response_data( # ty: ignore[invalid-return-type] data=data, - cast_to=cast_to, # type: ignore + cast_to=cast_to, response=response, ) @@ -332,13 +325,14 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # If the API responds with content that isn't JSON then we just return # the (decoded) text without performing any parsing so that you can still # handle the response however you need to. - return response.text # type: ignore + return response.text # ty: ignore[invalid-return-type] data = response.json() - return self._client._process_response_data( + # cast_to is validated above and preserves the response generic through dynamic parsing. + return self._client._process_response_data( # ty: ignore[invalid-return-type] data=data, - cast_to=cast_to, # type: ignore + cast_to=cast_to, response=response, ) @@ -364,7 +358,8 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]: extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} extra_headers[RAW_RESPONSE_HEADER] = "true" - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] return cast(LegacyAPIResponse[R], func(*args, **kwargs)) @@ -381,7 +376,8 @@ async def wrapped(*args: P.args, **kwargs: P.kwargs) -> LegacyAPIResponse[R]: extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} extra_headers[RAW_RESPONSE_HEADER] = "true" - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] return cast(LegacyAPIResponse[R], await func(*args, **kwargs)) diff --git a/src/openai/_models.py b/src/openai/_models.py index 2b3aa51921..fbb4388c6a 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -86,7 +86,7 @@ if TYPE_CHECKING: from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler from pydantic_core import CoreSchema, core_schema - from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema + from pydantic_core.core_schema import ModelField else: try: from pydantic_core import CoreSchema, core_schema @@ -116,12 +116,12 @@ class BaseModel(pydantic.BaseModel): @override def model_fields_set(self) -> set[str]: # a forwards-compat shim for pydantic v2 - return self.__fields_set__ # type: ignore + return self.__fields_set__ - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - extra: Any = pydantic.Extra.allow # type: ignore + class Config(pydantic.BaseConfig): + extra: Any = pydantic.Extra.allow - @pydantic.root_validator(pre=True) # pyright: ignore[reportDeprecated] + @pydantic.root_validator(pre=True) @classmethod def _preserve_wire_aliases(cls, values: Any) -> Any: if not is_dict(values): @@ -242,14 +242,13 @@ def to_json( @override def __str__(self) -> str: - # mypy complains about an invalid self arg - return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] + return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # Override the 'construct' method in a way that supports recursive parsing without validation. # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. @classmethod @override - def construct( # pyright: ignore[reportIncompatibleMethodOverride] + def construct( __cls: Type[ModelT], _fields_set: set[str] | None = None, **values: object, @@ -296,7 +295,7 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] if PYDANTIC_V1: # init_private_attributes() does not exist in v2 - m._init_private_attributes() # type: ignore + m._init_private_attributes() # copied from Pydantic v1's `construct()` method object.__setattr__(m, "__fields_set__", _fields_set) @@ -380,7 +379,7 @@ def model_dump( raise ValueError("fallback is only supported in Pydantic v2") if exclude_computed_fields != False: raise ValueError("exclude_computed_fields is only supported in Pydantic v2") - dumped = super().dict( # pyright: ignore[reportDeprecated] + dumped = super().dict( include=include, exclude=exclude, by_alias=by_alias if by_alias is not None else False, @@ -442,7 +441,7 @@ def model_dump_json( raise ValueError("ensure_ascii is only supported in Pydantic v2") if exclude_computed_fields != False: raise ValueError("exclude_computed_fields is only supported in Pydantic v2") - return super().json( # type: ignore[reportDeprecated] + return super().json( indent=indent, include=include, exclude=exclude, @@ -528,9 +527,9 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: return field_get_default(field) if PYDANTIC_V1: - type_ = cast(type, field.outer_type_) # type: ignore + type_ = cast(type, field.outer_type_) else: - type_ = field.annotation # type: ignore + type_ = field.annotation if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") @@ -549,8 +548,8 @@ def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: if fields["type"] == "model-fields": extras = fields.get("extras_schema") if extras and "cls" in extras: - # mypy can't narrow the type - return extras["cls"] # type: ignore[no-any-return] + # Pydantic core-schema metadata stores the model class as an object. + return extras["cls"] # ty: ignore[invalid-return-type] return None @@ -620,8 +619,8 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] # `Literal['value']` will be reported as a type error by type checkers type_ = cast("type[object]", type_) if is_type_alias_type(type_): - original_type = type_ # type: ignore[unreachable] - type_ = type_.__value__ # type: ignore[unreachable] + original_type = type_ + type_ = type_.__value__ # unwrap `Annotated[T, ...]` -> `T` if metadata is not None and len(metadata) > 0: @@ -639,22 +638,22 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] if is_union(origin): try: - return validate_type(type_=cast("type[object]", original_type or type_), value=value) + return validate_type(type_=original_type or type_, value=value) except Exception: pass # if the type is a discriminated union then we want to construct the right variant # in the union, even if the data doesn't match exactly, otherwise we'd break code # that relies on the constructed class types, e.g. - # + # class FooType: # kind: Literal['foo'] # value: str - # + # class BarType: # kind: Literal['bar'] # value: int - # + # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then # we'd end up constructing `FooType` when it should be `BarType`. discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta) @@ -692,7 +691,8 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] if is_mapping(value): if issubclass(type_, BaseModel): - return type_.construct(**value) # type: ignore[arg-type] + # Preserve unchecked construction; input keys may include Pydantic control fields. + return type_.construct(**value) # ty: ignore[invalid-argument-type] return cast(Any, type_).construct(**value) @@ -714,13 +714,15 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] if type_ == datetime: try: - return parse_datetime(value) # type: ignore + # Try coercion on arbitrary input; failed parses fall back to the original value. + return parse_datetime(value) # ty: ignore[invalid-argument-type] except Exception: return value if type_ == date: try: - return parse_date(value) # type: ignore + # Try coercion on arbitrary input; failed parses fall back to the original value. + return parse_date(value) # ty: ignore[invalid-argument-type] except Exception: return value @@ -802,7 +804,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, variant = strip_annotated_type(variant) if is_basemodel_type(variant): if PYDANTIC_V1: - field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + field_info = variant.__fields__.get(discriminator_field_name) if not field_info: continue @@ -824,7 +826,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, field_schema = field["schema"] if field_schema["type"] == "literal": - for entry in cast("LiteralSchema", field_schema)["expected"]: + for entry in field_schema["expected"]: if isinstance(entry, str): mapping[entry] = variant @@ -852,17 +854,15 @@ def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelF if schema["type"] != "model": return None - schema = cast("ModelSchema", schema) fields_schema = schema["schema"] if fields_schema["type"] != "model-fields": return None - fields_schema = cast("ModelFieldsSchema", fields_schema) field = fields_schema["fields"].get(field_name) if not field: return None - return cast("ModelField", field) # pyright: ignore[reportUnnecessaryCast] + return field def validate_type(*, type_: type[_T], value: object) -> _T: @@ -870,7 +870,7 @@ def validate_type(*, type_: type[_T], value: object) -> _T: if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): return cast(_T, parse_obj(type_, value)) - return cast(_T, _validate_non_model_type(type_=type_, value=value)) + return _validate_non_model_type(type_=type_, value=value) def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: @@ -889,7 +889,7 @@ def add_request_id(obj: BaseModel, request_id: str | None) -> None: # case so we need to explicitly exclude it if PYDANTIC_V1: try: - exclude_fields = obj.__exclude_fields__ # type: ignore + exclude_fields = obj.__exclude_fields__ except AttributeError: cast(Any, obj).__exclude_fields__ = {"_request_id", "__exclude_fields__"} else: @@ -939,7 +939,7 @@ def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: return cast(_T, model.__root__) def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]: - return RootModel[type_] # type: ignore + return RootModel[type_] class SecurityOptions(TypedDict, total=False): @@ -990,7 +990,7 @@ class FinalRequestOptions(pydantic.BaseModel): if PYDANTIC_V1: - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] + class Config(pydantic.BaseConfig): arbitrary_types_allowed: bool = True else: model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) @@ -1012,10 +1012,10 @@ def _strip_raw_response_header(self) -> None: # this is necessary as we don't want to do any actual runtime type checking # (which means we can't use validators) but we do want to ensure that `NotGiven` # values are not present - # + # type ignore required because we're adding explicit types to `**values` @classmethod - def construct( # type: ignore + def construct( # ty: ignore[invalid-method-override] cls, _fields_set: set[str] | None = None, **values: Unpack[FinalRequestOptionsInput], @@ -1027,7 +1027,7 @@ def construct( # type: ignore for key, value in values.items() } if PYDANTIC_V1: - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + return super().construct(_fields_set, **kwargs) return super().model_construct(_fields_set, **kwargs) if not TYPE_CHECKING: diff --git a/src/openai/_provider.py b/src/openai/_provider.py index 8a6c83e502..c2deb6b7e7 100644 --- a/src/openai/_provider.py +++ b/src/openai/_provider.py @@ -44,17 +44,17 @@ def configure(self) -> _ProviderRuntime: ... _provider_definitions: WeakKeyDictionary[_Provider, _ProviderDefinition] = WeakKeyDictionary() -def _create_provider(definition: _ProviderDefinition) -> _Provider: # pyright: ignore[reportUnusedFunction] +def _create_provider(definition: _ProviderDefinition) -> _Provider: provider = _Provider() _provider_definitions[provider] = definition return provider -def _provider_name(provider: _Provider) -> str: # pyright: ignore[reportUnusedFunction] +def _provider_name(provider: _Provider) -> str: return _get_provider_definition(provider).name -def _configure_provider(provider: _Provider) -> _ProviderRuntime: # pyright: ignore[reportUnusedFunction] +def _configure_provider(provider: _Provider) -> _ProviderRuntime: return _get_provider_definition(provider).configure() diff --git a/src/openai/_response.py b/src/openai/_response.py index 41bddf671a..025c1986c8 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -131,7 +131,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # unwrap `TypeAlias('Name', T)` -> `T` if is_type_alias_type(cast_to): - cast_to = cast_to.__value__ # type: ignore[unreachable] + cast_to = cast_to.__value__ # unwrap `Annotated[T, ...]` -> `T` if cast_to and is_annotated_type(cast_to): @@ -203,7 +203,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # handle the legacy binary response case if inspect.isclass(cast_to) and cast_to.__name__ == "HttpxBinaryResponseContent": - return cast(R, cast_to(response)) # type: ignore + return cast_to(response) if origin == APIResponse: raise RuntimeError("Unexpected state - cast_to is `APIResponse`") @@ -219,13 +219,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: raise ValueError("Subclasses of HTTP response classes cannot be passed to `cast_to`") return cast(R, response) - if ( - inspect.isclass( - origin # pyright: ignore[reportUnknownArgumentType] - ) - and not issubclass(origin, BaseModel) - and issubclass(origin, pydantic.BaseModel) - ): + if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel): raise TypeError("Pydantic models must subclass our base model type, e.g. `from openai import BaseModel`") if ( @@ -249,9 +243,10 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: except Exception as exc: log.debug("Could not read JSON from response data due to %s", type(exc).__name__) else: - return self._client._process_response_data( + # cast_to is validated above and preserves the response generic through dynamic parsing. + return self._client._process_response_data( # ty: ignore[invalid-return-type] data=data, - cast_to=cast_to, # type: ignore + cast_to=cast_to, response=response, ) @@ -265,13 +260,14 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # If the API responds with content that isn't JSON then we just return # the (decoded) text without performing any parsing so that you can still # handle the response however you need to. - return response.text # type: ignore + return response.text # ty: ignore[invalid-return-type] data = response.json() - return self._client._process_response_data( + # cast_to is validated above and preserves the response generic through dynamic parsing. + return self._client._process_response_data( # ty: ignore[invalid-return-type] data=data, - cast_to=cast_to, # type: ignore + cast_to=cast_to, response=response, ) @@ -279,7 +275,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: class APIResponse(BaseAPIResponse[R]): @property def request_id(self) -> str | None: - return self.http_response.headers.get("x-request-id") # type: ignore[no-any-return] + return self.http_response.headers.get("x-request-id") @overload def parse(self, *, to: type[_T]) -> _T: ... @@ -320,7 +316,7 @@ class MyModel(BaseModel): cache_key = to if to is not None else self._cast_to cached = self._parsed_by_type.get(cache_key) if cached is not None: - return cached # type: ignore[no-any-return] + return cached if not self._is_sse_stream: self.read() @@ -388,7 +384,7 @@ def iter_lines(self) -> Iterator[str]: class AsyncAPIResponse(BaseAPIResponse[R]): @property def request_id(self) -> str | None: - return self.http_response.headers.get("x-request-id") # type: ignore[no-any-return] + return self.http_response.headers.get("x-request-id") @overload async def parse(self, *, to: type[_T]) -> _T: ... @@ -427,7 +423,7 @@ class MyModel(BaseModel): cache_key = to if to is not None else self._cast_to cached = self._parsed_by_type.get(cache_key) if cached is not None: - return cached # type: ignore[no-any-return] + return cached if not self._is_sse_stream: await self.read() @@ -675,7 +671,8 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResp extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} extra_headers[RAW_RESPONSE_HEADER] = "stream" - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] make_request = functools.partial(func, *args, **kwargs) @@ -696,7 +693,8 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[As extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} extra_headers[RAW_RESPONSE_HEADER] = "stream" - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] make_request = func(*args, **kwargs) @@ -721,7 +719,8 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIRes extra_headers[RAW_RESPONSE_HEADER] = "stream" extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] make_request = functools.partial(func, *args, **kwargs) @@ -746,7 +745,8 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_A extra_headers[RAW_RESPONSE_HEADER] = "stream" extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] make_request = func(*args, **kwargs) @@ -765,7 +765,8 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} extra_headers[RAW_RESPONSE_HEADER] = "raw" - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] return cast(APIResponse[R], func(*args, **kwargs)) @@ -782,7 +783,8 @@ async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]: extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} extra_headers[RAW_RESPONSE_HEADER] = "raw" - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] return cast(AsyncAPIResponse[R], await func(*args, **kwargs)) @@ -805,7 +807,8 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT: extra_headers[RAW_RESPONSE_HEADER] = "raw" extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] return cast(_APIResponseT, func(*args, **kwargs)) @@ -828,7 +831,8 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]: extra_headers[RAW_RESPONSE_HEADER] = "raw" extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - kwargs["extra_headers"] = extra_headers + # All wrapped SDK request methods accept extra_headers; ParamSpec cannot express this constraint. + kwargs["extra_headers"] = extra_headers # ty: ignore[invalid-assignment] return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs)) diff --git a/src/openai/_utils/_compat.py b/src/openai/_utils/_compat.py index 03881b595a..1100c63cc4 100644 --- a/src/openai/_utils/_compat.py +++ b/src/openai/_utils/_compat.py @@ -22,11 +22,11 @@ def get_origin(tp: type[Any]) -> type[Any] | None: def is_union(tp: Optional[Type[Any]]) -> bool: if sys.version_info < (3, 10): - return tp is Union # type: ignore[comparison-overlap] + return tp is Union else: import types - return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] + return tp is Union or tp is types.UnionType def is_typeddict(tp: Type[Any]) -> bool: diff --git a/src/openai/_utils/_datetime_parse.py b/src/openai/_utils/_datetime_parse.py index 7cb9d9e668..eac167c457 100644 --- a/src/openai/_utils/_datetime_parse.py +++ b/src/openai/_utils/_datetime_parse.py @@ -100,7 +100,8 @@ def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} kw_["tzinfo"] = tzinfo - return datetime(**kw_) # type: ignore + # Regex group names determine each argument type; the dictionary loses that correlation. + return datetime(**kw_) # ty: ignore[invalid-argument-type] def parse_date(value: Union[date, StrBytesIntFloat]) -> date: diff --git a/src/openai/_utils/_proxy.py b/src/openai/_utils/_proxy.py index 0f239a33c6..1d6f3443d3 100644 --- a/src/openai/_utils/_proxy.py +++ b/src/openai/_utils/_proxy.py @@ -19,7 +19,7 @@ class LazyProxy(Generic[T], ABC): def __getattr__(self, attr: str) -> object: proxied = self.__get_proxied__() if isinstance(proxied, LazyProxy): - return proxied # pyright: ignore + return proxied return getattr(proxied, attr) @override @@ -43,9 +43,9 @@ def __dir__(self) -> Iterable[str]: return [] return proxied.__dir__() - @property # type: ignore + @property @override - def __class__(self) -> type: # pyright: ignore + def __class__(self) -> type: try: proxied = self.__get_proxied__() except Exception: diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 7316075d4d..9de460b7f5 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -202,7 +202,7 @@ def _transform_recursive( if _no_transform_needed(inner_type): # for some types there is no need to transform anything, so we can get a small # perf boost from skipping that work. - # + # but we still need to convert to a list to ensure the data is json-serializable if is_list(data): return data @@ -212,7 +212,7 @@ def _transform_recursive( if is_union_type(stripped_type): # For union types we run the transformation against all subtypes to ensure that everything is transformed. - # + # TODO: there may be edge cases where the same normalized field name will transform to two different names # in different subtypes. for subtype in get_args(stripped_type): @@ -251,7 +251,7 @@ def _format_data(data: object, format_: PropertyFormat, format_template: str | N elif isinstance(data, io.IOBase): binary = data.read() - if isinstance(binary, str): # type: ignore[unreachable] + if isinstance(binary, str): binary = binary.encode() if not isinstance(binary, bytes): @@ -370,7 +370,7 @@ async def _async_transform_recursive( if _no_transform_needed(inner_type): # for some types there is no need to transform anything, so we can get a small # perf boost from skipping that work. - # + # but we still need to convert to a list to ensure the data is json-serializable if is_list(data): return data @@ -380,7 +380,7 @@ async def _async_transform_recursive( if is_union_type(stripped_type): # For union types we run the transformation against all subtypes to ensure that everything is transformed. - # + # TODO: there may be edge cases where the same normalized field name will transform to two different names # in different subtypes. for subtype in get_args(stripped_type): @@ -419,7 +419,7 @@ async def _async_format_data(data: object, format_: PropertyFormat, format_templ elif isinstance(data, io.IOBase): binary = data.read() - if isinstance(binary, str): # type: ignore[unreachable] + if isinstance(binary, str): binary = binary.encode() if not isinstance(binary, bytes): diff --git a/src/openai/_utils/_typing.py b/src/openai/_utils/_typing.py index ed43d9d64c..8f6932ce00 100644 --- a/src/openai/_utils/_typing.py +++ b/src/openai/_utils/_typing.py @@ -15,7 +15,6 @@ ) from ._utils import lru_cache -from .._types import InheritsGeneric from ._compat import is_union as _is_union @@ -53,7 +52,7 @@ def is_not_required_type(typ: type) -> bool: def is_typevar(typ: type) -> bool: # type ignore is required because type checkers # think this expression will always return False - return type(typ) == TypeVar # type: ignore + return type(typ) == TypeVar _TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) @@ -120,7 +119,7 @@ class MyResponse(Foo[_T]): ``` """ cls = cast(object, get_origin(typ) or typ) - if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] + if cls in generic_bases: # we're given the class directly return extract_type_arg(typ, index) @@ -130,9 +129,10 @@ class MyResponse(Foo[_T]): # because it is intended to be for internal use only, however there does # not seem to be a way to resolve generic TypeVars for inherited subclasses # without using it. - if isinstance(cls, InheritsGeneric): + orig_bases = getattr(cls, "__orig_bases__", None) + if isinstance(orig_bases, tuple): target_base_class: Any | None = None - for base in cls.__orig_bases__: + for base in orig_bases: if base.__origin__ in generic_bases: target_base_class = base break @@ -150,7 +150,7 @@ class MyResponse(Foo[_T]): # then that means the subclass itself is generic, so we have # to resolve the type argument from the class itself, not # the base class. - # + # Note: if there is more than 1 type argument, the subclass could # change the ordering of the type arguments, this is not currently # supported. diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index 95641eb158..fdec0160aa 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -165,7 +165,7 @@ def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: # The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], # however this cause Pyright to rightfully report errors. As we know we don't # care about the contained types we can safely use `object` in its place. -# + # There are two separate functions defined, `is_*` and `is_*_t` for different use cases. # `is_*` is for when you're dealing with an unknown input # `is_*_t` is for when you're narrowing a known union type to a specific subset @@ -269,7 +269,7 @@ def wrapper(*args: object, **kwargs: object) -> object: given_params.add(positional[i]) except IndexError: raise TypeError( - f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given" + f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given" # ty: ignore[unresolved-attribute] ) from None for key in kwargs.keys(): @@ -297,7 +297,8 @@ def wrapper(*args: object, **kwargs: object) -> object: raise TypeError(msg) return func(*args, **kwargs) - return wrapper # type: ignore + # The decorator forwards the original callable, including its runtime argument validation. + return wrapper # ty: ignore[invalid-return-type] return inner @@ -388,8 +389,7 @@ def file_from_path(path: str) -> FileTypes: def get_required_header(headers: HeadersLike, header: str) -> str: lower_header = header.lower() if is_mapping_t(headers): - # mypy doesn't understand the type narrowing here - for k, v in headers.items(): # type: ignore + for k, v in headers.items(): if k.lower() == lower_header and isinstance(v, str): return v @@ -418,7 +418,7 @@ def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: wrapper = functools.lru_cache( # noqa: TID251 maxsize=maxsize, ) - return cast(Any, wrapper) # type: ignore[no-any-return] + return wrapper def json_safe(data: object) -> object: diff --git a/src/openai/auth/_workload.py b/src/openai/auth/_workload.py index 4f9797f092..0a54312750 100644 --- a/src/openai/auth/_workload.py +++ b/src/openai/auth/_workload.py @@ -235,7 +235,7 @@ def get_token(self) -> str: if self._refreshing: while self._refreshing: self._condition.wait() - token = self._cached_token # type: ignore[unreachable] + token = self._cached_token if self._token_unusable(): raise RuntimeError("Token is unusable after refresh completed") return cast(str, token) diff --git a/src/openai/helpers/local_audio_player.py b/src/openai/helpers/local_audio_player.py index 8d8cb3d340..a88498b892 100644 --- a/src/openai/helpers/local_audio_player.py +++ b/src/openai/helpers/local_audio_player.py @@ -1,4 +1,3 @@ -# mypy: ignore-errors from __future__ import annotations import queue diff --git a/src/openai/helpers/microphone.py b/src/openai/helpers/microphone.py index 5a1e8ae87d..375853687a 100644 --- a/src/openai/helpers/microphone.py +++ b/src/openai/helpers/microphone.py @@ -1,4 +1,3 @@ -# mypy: ignore-errors from __future__ import annotations import io @@ -23,7 +22,8 @@ class Microphone(Generic[DType]): def __init__( self, channels: int = 1, - dtype: Type[DType] = np.int16, + # The historical generic default is int16; callers may select another dtype. + dtype: Type[DType] = np.int16, # ty: ignore[invalid-parameter-default] should_record: Union[Callable[[], bool], None] = None, timeout: Union[float, None] = None, ): diff --git a/src/openai/lib/_assistants_runs.py b/src/openai/lib/_assistants_runs.py index 6e750e1fc2..8de8c3d212 100644 --- a/src/openai/lib/_assistants_runs.py +++ b/src/openai/lib/_assistants_runs.py @@ -71,7 +71,7 @@ def runs_create_and_poll( lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = self.create( # pyright: ignore[reportDeprecated] + run = self.create( thread_id=thread_id, assistant_id=assistant_id, include=include, @@ -97,7 +97,7 @@ def runs_create_and_poll( extra_body=extra_body, timeout=timeout, ) - return self.poll( # pyright: ignore[reportDeprecated] + return self.poll( run.id, thread_id=thread_id, extra_headers=extra_headers, @@ -207,7 +207,7 @@ def runs_poll( terminal_states = {"requires_action", "cancelled", "completed", "failed", "expired", "incomplete"} while True: - response = self.with_raw_response.retrieve( # pyright: ignore[reportDeprecated] + response = self.with_raw_response.retrieve( thread_id=thread_id, run_id=run_id, extra_headers=extra_headers, @@ -329,7 +329,7 @@ def runs_submit_tool_outputs_and_poll( More information on Run lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = self.submit_tool_outputs( # pyright: ignore[reportDeprecated] + run = self.submit_tool_outputs( run_id=run_id, thread_id=thread_id, tool_outputs=tool_outputs, @@ -339,7 +339,7 @@ def runs_submit_tool_outputs_and_poll( extra_body=extra_body, timeout=timeout, ) - return self.poll( # pyright: ignore[reportDeprecated] + return self.poll( run_id=run.id, thread_id=thread_id, extra_headers=extra_headers, @@ -439,7 +439,7 @@ async def async_runs_create_and_poll( lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = await self.create( # pyright: ignore[reportDeprecated] + run = await self.create( thread_id=thread_id, assistant_id=assistant_id, include=include, @@ -465,7 +465,7 @@ async def async_runs_create_and_poll( extra_body=extra_body, timeout=timeout, ) - return await self.poll( # pyright: ignore[reportDeprecated] + return await self.poll( run.id, thread_id=thread_id, extra_headers=extra_headers, @@ -572,7 +572,7 @@ async def async_runs_poll( terminal_states = {"requires_action", "cancelled", "completed", "failed", "expired", "incomplete"} while True: - response = await self.with_raw_response.retrieve( # pyright: ignore[reportDeprecated] + response = await self.with_raw_response.retrieve( thread_id=thread_id, run_id=run_id, extra_headers=extra_headers, @@ -693,7 +693,7 @@ async def async_runs_submit_tool_outputs_and_poll( More information on Run lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = await self.submit_tool_outputs( # pyright: ignore[reportDeprecated] + run = await self.submit_tool_outputs( run_id=run_id, thread_id=thread_id, tool_outputs=tool_outputs, @@ -703,7 +703,7 @@ async def async_runs_submit_tool_outputs_and_poll( extra_body=extra_body, timeout=timeout, ) - return await self.poll( # pyright: ignore[reportDeprecated] + return await self.poll( run_id=run.id, thread_id=thread_id, extra_headers=extra_headers, diff --git a/src/openai/lib/_assistants_threads.py b/src/openai/lib/_assistants_threads.py index ab3754f4e0..9ff812a7a0 100644 --- a/src/openai/lib/_assistants_threads.py +++ b/src/openai/lib/_assistants_threads.py @@ -63,7 +63,7 @@ def threads_create_and_run_poll( More information on Run lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = self.create_and_run( # pyright: ignore[reportDeprecated] + run = self.create_and_run( assistant_id=assistant_id, instructions=instructions, max_completion_tokens=max_completion_tokens, @@ -85,7 +85,7 @@ def threads_create_and_run_poll( extra_body=extra_body, timeout=timeout, ) - return self.runs.poll(run.id, run.thread_id, extra_headers, extra_query, extra_body, timeout, poll_interval_ms) # pyright: ignore[reportDeprecated] + return self.runs.poll(run.id, run.thread_id, extra_headers, extra_query, extra_body, timeout, poll_interval_ms) def threads_create_and_run_stream( @@ -190,7 +190,7 @@ async def async_threads_create_and_run_poll( More information on Run lifecycles can be found here: https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps """ - run = await self.create_and_run( # pyright: ignore[reportDeprecated] + run = await self.create_and_run( assistant_id=assistant_id, instructions=instructions, max_completion_tokens=max_completion_tokens, @@ -212,7 +212,7 @@ async def async_threads_create_and_run_poll( extra_body=extra_body, timeout=timeout, ) - return await self.runs.poll( # pyright: ignore[reportDeprecated] + return await self.runs.poll( run.id, run.thread_id, extra_headers, extra_query, extra_body, timeout, poll_interval_ms ) diff --git a/src/openai/lib/_bedrock_auth.py b/src/openai/lib/_bedrock_auth.py index e9076ef210..6c78900d26 100644 --- a/src/openai/lib/_bedrock_auth.py +++ b/src/openai/lib/_bedrock_auth.py @@ -1,5 +1,3 @@ -# pyright: reportMissingTypeStubs=false - from __future__ import annotations import os @@ -27,10 +25,10 @@ def get_credentials(self) -> object | None: ... def _load_botocore() -> tuple[Any, Any, Any, Any]: try: - from botocore.auth import SigV4Auth # type: ignore[import-untyped] - from botocore.session import Session # type: ignore[import-untyped] - from botocore.awsrequest import AWSRequest # type: ignore[import-untyped] - from botocore.credentials import Credentials # type: ignore[import-untyped] + from botocore.auth import SigV4Auth + from botocore.session import Session + from botocore.awsrequest import AWSRequest + from botocore.credentials import Credentials except ImportError as exc: raise OpenAIError( "Bedrock AWS authentication requires optional AWS dependencies. " diff --git a/src/openai/lib/_chat_completion_resources.py b/src/openai/lib/_chat_completion_resources.py index 038448c25f..a33fbb52d8 100644 --- a/src/openai/lib/_chat_completion_resources.py +++ b/src/openai/lib/_chat_completion_resources.py @@ -1,7 +1,7 @@ from __future__ import annotations import inspect -from typing import TYPE_CHECKING, Dict, List, Type, Union, Iterable, Optional, cast +from typing import TYPE_CHECKING, Dict, List, Type, Union, Callable, Iterable, Optional, cast from functools import partial from typing_extensions import Literal @@ -329,7 +329,7 @@ def stream( **(extra_headers or {}), } - api_request: partial[Stream[ChatCompletionChunk]] = partial( + api_request: Callable[[], Stream[ChatCompletionChunk]] = partial( resource.create, messages=messages, model=model, diff --git a/src/openai/lib/_client_auth.py b/src/openai/lib/_client_auth.py index b4039c1e21..c5f3f92208 100644 --- a/src/openai/lib/_client_auth.py +++ b/src/openai/lib/_client_auth.py @@ -139,7 +139,8 @@ def sync__init__( api_key = _sdk_client.os.environ.get("OPENAI_API_KEY") if callable(api_key): self.api_key = "" - self._api_key_provider = api_key + # Preserve callable-first handling, including callable str subclasses. + self._api_key_provider = api_key # ty: ignore[invalid-assignment] else: self.api_key = api_key or "" self._api_key_provider = None @@ -602,7 +603,8 @@ def async__init__( api_key = _sdk_client.os.environ.get("OPENAI_API_KEY") if callable(api_key): self.api_key = "" - self._api_key_provider = api_key + # Preserve callable-first handling, including callable str subclasses. + self._api_key_provider = api_key # ty: ignore[invalid-assignment] else: self.api_key = api_key or "" self._api_key_provider = None diff --git a/src/openai/lib/_module_runtime.py b/src/openai/lib/_module_runtime.py index cb64ffd9ca..e99fc4998c 100644 --- a/src/openai/lib/_module_runtime.py +++ b/src/openai/lib/_module_runtime.py @@ -40,7 +40,8 @@ def load_client() -> OpenAI: else: _sdk.api_type = "openai" if _sdk.api_type == "azure": - _sdk._client = _sdk._AzureModuleClient( # type: ignore + # Optional module settings are resolved and validated by AzureOpenAI at runtime. + _sdk._client = _sdk._AzureModuleClient( # ty: ignore[no-matching-overload] api_version=_sdk.api_version, azure_endpoint=_sdk.azure_endpoint, api_key=_sdk.api_key, diff --git a/src/openai/lib/_parsing/_audio.py b/src/openai/lib/_parsing/_audio.py index cd76e23ad2..9b429708a7 100644 --- a/src/openai/lib/_parsing/_audio.py +++ b/src/openai/lib/_parsing/_audio.py @@ -18,7 +18,7 @@ def get_transcription_response_format_type( *, log: logging.Logger, ) -> type[Transcription | TranscriptionVerbose | TranscriptionDiarized | str]: - if isinstance(response_format, Omit) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] + if isinstance(response_format, Omit) or response_format is None: return Transcription if response_format == "json": @@ -29,7 +29,7 @@ def get_transcription_response_format_type( return TranscriptionDiarized elif response_format == "srt" or response_format == "text" or response_format == "vtt": return str - elif TYPE_CHECKING: # type: ignore[unreachable] + elif TYPE_CHECKING: assert_never(response_format) else: log.warning("Unexpected audio response format: %s", response_format) @@ -41,7 +41,7 @@ def get_translation_response_format_type( *, log: logging.Logger, ) -> type[Translation | TranslationVerbose | str]: - if isinstance(response_format, Omit) or response_format is None: # pyright: ignore[reportUnnecessaryComparison] + if isinstance(response_format, Omit) or response_format is None: return Translation if response_format == "json": @@ -50,7 +50,7 @@ def get_translation_response_format_type( return TranslationVerbose elif response_format == "srt" or response_format == "text" or response_format == "vtt": return str - elif TYPE_CHECKING and response_format != "diarized_json": # type: ignore[unreachable] + elif TYPE_CHECKING and response_format != "diarized_json": assert_never(response_format) else: log.warning("Unexpected audio response format: %s", response_format) diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index 21be8ace54..0bfdced0e5 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -141,7 +141,7 @@ def parse_chat_completion( tool_call.custom.name, stacklevel=2, ) - elif TYPE_CHECKING: # type: ignore[unreachable] + elif TYPE_CHECKING: assert_never(tool_call) else: tool_calls.append(tool_call) @@ -194,7 +194,7 @@ def parse_function_tool_arguments( if not input_fn.get("strict"): return None - return json.loads(function.arguments) # type: ignore[no-any-return] + return json.loads(function.arguments) def maybe_parse_content( diff --git a/src/openai/lib/_parsing/_embeddings.py b/src/openai/lib/_parsing/_embeddings.py index e64185e1b5..92e0bfb553 100644 --- a/src/openai/lib/_parsing/_embeddings.py +++ b/src/openai/lib/_parsing/_embeddings.py @@ -34,9 +34,7 @@ def parse_embedding_response( # use array for base64 optimisation embedding.embedding = array.array("f", base64.b64decode(data)).tolist() else: - embedding.embedding = np.frombuffer( # type: ignore[no-untyped-call] - base64.b64decode(data), dtype="float32" - ).tolist() + embedding.embedding = np.frombuffer(base64.b64decode(data), dtype="float32").tolist() return obj diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 0a2e03b69a..1f2f0b4b3d 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -26,7 +26,6 @@ ResponseFormatTextConfigParam, ParsedResponseFunctionToolCall, ) -from ...types.chat.completion_create_params import ResponseFormat from ...types.responses.namespace_tool_param import ToolFunction TextFormatT = TypeVar( @@ -39,7 +38,6 @@ def type_to_text_format_param(type_: type) -> ResponseFormatTextConfigParam: response_format_dict = type_to_response_format_param(type_) assert is_given(response_format_dict) - response_format_dict = cast(ResponseFormat, response_format_dict) # pyright: ignore[reportUnnecessaryCast] assert response_format_dict["type"] == "json_schema" assert "schema" in response_format_dict["json_schema"] @@ -130,7 +128,7 @@ def parse_response( or output.type == "custom_tool_call_output" ): output_list.append(output) - elif TYPE_CHECKING: # type: ignore + elif TYPE_CHECKING: assert_never(output) else: output_list.append(output) diff --git a/src/openai/lib/_response_resources.py b/src/openai/lib/_response_resources.py index 76dff89ae6..27795b7a8d 100644 --- a/src/openai/lib/_response_resources.py +++ b/src/openai/lib/_response_resources.py @@ -1,7 +1,7 @@ from __future__ import annotations from copy import copy -from typing import TYPE_CHECKING, Any, List, Type, Union, Iterable, Optional, cast +from typing import TYPE_CHECKING, Any, List, Type, Union, Callable, Iterable, Optional, cast from functools import partial from typing_extensions import Literal @@ -369,7 +369,7 @@ def stream( text = copy(text) text["format"] = _type_to_text_format_param(text_format) - api_request: partial[Stream[ResponseStreamEvent]] = partial( + api_request: Callable[[], Stream[ResponseStreamEvent]] = partial( resource.create, access_programs=access_programs, input=input, @@ -621,7 +621,7 @@ def _make_tools(tools: Iterable[ParseableToolParam] | Omit) -> List[ToolParam] | converted_tools.append(tool) continue - function = cast(Any, tool)["function"] # pyright: ignore[reportUnnecessaryCast] + function = cast(Any, tool)["function"] if not isinstance(function, PydanticFunctionTool): raise Exception( "Expected Chat Completions function tool shape to be created using `openai.pydantic_function_tool()`" diff --git a/src/openai/lib/_vector_stores.py b/src/openai/lib/_vector_stores.py index 90508ceee1..1f99867041 100644 --- a/src/openai/lib/_vector_stores.py +++ b/src/openai/lib/_vector_stores.py @@ -80,7 +80,7 @@ def poll_vector_store_file( elif file.status == "cancelled" or file.status == "completed" or file.status == "failed": return file else: - if TYPE_CHECKING: # type: ignore[unreachable] + if TYPE_CHECKING: assert_never(file.status) else: return file @@ -123,7 +123,7 @@ async def async_poll_vector_store_file( elif file.status == "cancelled" or file.status == "completed" or file.status == "failed": return file else: - if TYPE_CHECKING: # type: ignore[unreachable] + if TYPE_CHECKING: assert_never(file.status) else: return file @@ -522,7 +522,7 @@ async def asyncio_upload_file(semaphore: asyncio.Semaphore, file: FileTypes) -> await asyncio.gather(*tasks) elif async_library == "trio": # We only import if the library is being used. - import trio # type: ignore # pyright: ignore[reportMissingTypeStubs] + import trio async def trio_upload_file(limiter: trio.CapacityLimiter, file: FileTypes) -> None: async with limiter: @@ -536,7 +536,7 @@ async def trio_upload_file(limiter: trio.CapacityLimiter, file: FileTypes) -> No async with trio.open_nursery() as nursery: for file in files: - nursery.start_soon(trio_upload_file, limiter, file) # pyright: ignore [reportUnknownMemberType] + nursery.start_soon(trio_upload_file, limiter, file) else: raise RuntimeError( f"Async runtime {async_library} is not supported yet. Only asyncio or trio is supported", diff --git a/src/openai/lib/bedrock.py b/src/openai/lib/bedrock.py index 2779a419dd..64747749d0 100644 --- a/src/openai/lib/bedrock.py +++ b/src/openai/lib/bedrock.py @@ -718,7 +718,7 @@ def __init__( self._bedrock_provider = _provider self._bedrock_state = _state - self._bedrock_token_provider = cast("AsyncBedrockTokenProvider | None", _state.token_provider) + self._bedrock_token_provider = _state.token_provider self._uses_region_derived_base_url = _state.uses_region_derived_base_url canonical_endpoint = _parse_bedrock_endpoint_hostname(self.base_url.host) provider_region = ( diff --git a/src/openai/lib/beta/agents/_output.py b/src/openai/lib/beta/agents/_output.py index 6490fb6eae..6958bbe84b 100644 --- a/src/openai/lib/beta/agents/_output.py +++ b/src/openai/lib/beta/agents/_output.py @@ -59,4 +59,4 @@ def bind_output_type( stream._dispatcher = cast("ToolDispatcher | None", dispatcher) else: stream._dispatcher = cast("AsyncToolDispatcher | None", dispatcher) - return cast(ResponseT, response) + return response diff --git a/src/openai/lib/beta/agents/_schema.py b/src/openai/lib/beta/agents/_schema.py index 35abaedb03..cc8acd463f 100644 --- a/src/openai/lib/beta/agents/_schema.py +++ b/src/openai/lib/beta/agents/_schema.py @@ -1,7 +1,7 @@ from __future__ import annotations from copy import deepcopy -from typing import Any, cast +from typing import Any import pydantic @@ -15,8 +15,6 @@ def model_schema( # Pydantic v1 caches schema dictionaries. Input and output policies must not # mutate each other's schemas or the model's cache. schema = deepcopy( - model.json_schema() - if not PYDANTIC_V1 and isinstance(model, pydantic.TypeAdapter) - else model_json_schema(cast(type[pydantic.BaseModel], model)) + model.json_schema() if not PYDANTIC_V1 and isinstance(model, pydantic.TypeAdapter) else model_json_schema(model) ) return _ensure_strict_json_schema(schema, path=(), root=schema) if strict else schema diff --git a/src/openai/lib/beta/agents/_tools.py b/src/openai/lib/beta/agents/_tools.py index 1c9cf10ee3..6801b28676 100644 --- a/src/openai/lib/beta/agents/_tools.py +++ b/src/openai/lib/beta/agents/_tools.py @@ -151,7 +151,7 @@ def close(self) -> None: @overload -def pydantic_function_tool( # type: ignore[overload-overlap] +def pydantic_function_tool( model: type[_ModelT], *, handler: Callable[[_ModelT], Awaitable[object]], @@ -201,16 +201,14 @@ def pydantic_function_tool( class _FunctionToolDecorator(Protocol): @overload - def __call__( # type: ignore[overload-overlap] - self, function: Callable[..., Awaitable[object]] - ) -> FunctionTool[Awaitable[ToolOutput]]: ... + def __call__(self, function: Callable[..., Awaitable[object]]) -> FunctionTool[Awaitable[ToolOutput]]: ... @overload def __call__(self, function: Callable[..., object]) -> FunctionTool[ToolOutput]: ... @overload -def function_tool( # type: ignore[overload-overlap] +def function_tool( function: Callable[..., Awaitable[object]], *, name: str | None = None, @@ -332,7 +330,7 @@ async def invoke_async(arguments: pydantic.BaseModel) -> object: return pydantic_function_tool( model, handler=invoke_async if inspect.iscoroutinefunction(function) else invoke, - name=function.__name__ if name is None else name, + name=function.__name__ if name is None else name, # ty: ignore[unresolved-attribute] description=(inspect.getdoc(function) or "") if description is None else description, defer_loading=defer_loading, ) diff --git a/src/openai/lib/browser.py b/src/openai/lib/browser.py index 98ff011201..4627c25606 100644 --- a/src/openai/lib/browser.py +++ b/src/openai/lib/browser.py @@ -797,7 +797,7 @@ def _observed_state(value: object) -> BrowserObservationV1: reason = change.get("reason") if isinstance(reason, str): reason = str.__str__(reason) - if reason not in ("policy", "unsupported"): + if not isinstance(reason, str) or reason not in ("policy", "unsupported"): raise RuntimeError("Browser change is invalid.") projected.append( { @@ -811,7 +811,7 @@ def _observed_state(value: object) -> BrowserObservationV1: status = change.get("status") if isinstance(status, str): status = str.__str__(status) - if status not in ("blocked", "started", "completed", "failed"): + if not isinstance(status, str) or status not in ("blocked", "started", "completed", "failed"): raise RuntimeError("Browser change is invalid.") projected.append( { @@ -827,7 +827,7 @@ def _observed_state(value: object) -> BrowserObservationV1: dialog = change.get("kind") if isinstance(dialog, str): dialog = str.__str__(dialog) - if dialog not in ("alert", "confirm", "prompt", "beforeunload", "other"): + if not isinstance(dialog, str) or dialog not in ("alert", "confirm", "prompt", "beforeunload", "other"): raise RuntimeError("Browser change is invalid.") projected.append( { @@ -837,7 +837,7 @@ def _observed_state(value: object) -> BrowserObservationV1: "kind": dialog, } ) - elif kind in ("tab_opened", "tab_closed", "tab_switched", "navigation"): + elif isinstance(kind, str) and kind in ("tab_opened", "tab_closed", "tab_switched", "navigation"): projected.append( { "type": kind, @@ -893,7 +893,7 @@ def _state_origin(value: str) -> str: # Shared privately with the Responses ledger, which preserves non-sensitive URL paths. -def _legacy_state_url(value: str) -> str: # pyright: ignore[reportUnusedFunction] +def _legacy_state_url(value: str) -> str: parsed = urlsplit(value) if not parsed.scheme or (parsed.scheme in ("http", "https") and (not parsed.netloc or not parsed.hostname)): raise RuntimeError("Browser URL is invalid.") @@ -1181,9 +1181,9 @@ def _arguments(member: str, raw: str) -> dict[str, object]: and isinstance(value, list) and all(isinstance(s, str) for s in cast(list[object], value)) ) - or (kind == "amount" and _state_counter(cast(object, value))) + or (kind == "amount" and _state_counter(value)) or (kind == "timeout" and isinstance(value, int) and not isinstance(value, bool) and 1 <= value <= 30000) - or (kind == "region" and _zoom_region(cast(object, value))) + or (kind == "region" and _zoom_region(value)) or ( kind == "wait_text" and isinstance(value, str) @@ -1242,7 +1242,7 @@ def _read_refused(call: ResponseFunctionToolCall) -> _BrowserResult: def _check_method_flavor(driver: object, member: str, *, asynchronous: bool) -> None: method = inspect.getattr_static(driver, member, None) if isinstance(method, (classmethod, staticmethod)): - method = cast(Callable[..., object], method.__func__) # pyright: ignore[reportUnknownMemberType] + method = method.__func__ # A dynamic property cannot be classified without invoking user code. if callable(method): _check_callable_flavor(method, member, asynchronous=asynchronous) diff --git a/src/openai/lib/computer.py b/src/openai/lib/computer.py index 4872ad8684..d7f6d892ca 100644 --- a/src/openai/lib/computer.py +++ b/src/openai/lib/computer.py @@ -138,7 +138,8 @@ def _prepare(params: ResponseCreateParamsNonStreaming, max_steps: object) -> Res "tool_choice", }.intersection(cast(Mapping[str, object], extra_body)): raise ValueError("ComputerToolset extra_body cannot override runner-owned fields") - if request.get("stream") or request.get("background"): + # Validate untyped callers at runtime even though the typed request excludes streams. + if request.get("stream") or request.get("background"): # ty: ignore[redundant-condition] raise ValueError("ComputerToolset requires non-streaming, foreground responses") if request.get("previous_response_id") or request.get("conversation"): raise ValueError("Pass complete input history; conversation and previous_response_id are not supported") diff --git a/src/openai/lib/responses_tool_runner.py b/src/openai/lib/responses_tool_runner.py index 55b5064570..09b5b70298 100644 --- a/src/openai/lib/responses_tool_runner.py +++ b/src/openai/lib/responses_tool_runner.py @@ -1085,7 +1085,8 @@ def __init__( if eager and not stream: raise ValueError("Eager execution requires streaming.") if ( - params.get("stream") + # Reject stream=True from untyped callers; select streaming through run(), not params. + params.get("stream") # ty: ignore[redundant-condition] or params.get("background") or params.get("conversation") is not None or params.get("previous_response_id") is not None @@ -2073,7 +2074,8 @@ def settle() -> None: if pool is None: pool = ThreadPoolExecutor(max_workers=max_concurrent_calls) jobs.append( - (item, pool.submit(copy_context().run, self._execute_function, run, item)) + # Context.run forwards the callable result, which is FunctionCallOutput here. + (item, pool.submit(copy_context().run, self._execute_function, run, item)) # ty: ignore[invalid-argument-type] ) if len(jobs) == max_concurrent_calls: settle() diff --git a/src/openai/lib/streaming/_assistants.py b/src/openai/lib/streaming/_assistants.py index 676ffe6383..79b07fbba5 100644 --- a/src/openai/lib/streaming/_assistants.py +++ b/src/openai/lib/streaming/_assistants.py @@ -417,7 +417,7 @@ def _emit_sse_event(self, event: AssistantStreamEvent) -> None: ... else: # we only want to error at build-time - if TYPE_CHECKING: # type: ignore[unreachable] + if TYPE_CHECKING: assert_never(event) self._current_event = None @@ -849,7 +849,7 @@ async def _emit_sse_event(self, event: AssistantStreamEvent) -> None: ... else: # we only want to error at build-time - if TYPE_CHECKING: # type: ignore[unreachable] + if TYPE_CHECKING: assert_never(event) self._current_event = None @@ -972,7 +972,7 @@ def accumulate_event( cast( MessageContent, construct_type( - # mypy doesn't allow Content for some reason + # MessageContent is a union alias; construct_type accepts it at runtime. type_=cast(Any, MessageContent), value=model_dump(content_delta, exclude_unset=True, warnings=False), ), @@ -993,8 +993,7 @@ def accumulate_event( current_message_snapshot.content[content_delta.index] = cast( MessageContent, construct_type( - # mypy doesn't allow Content for some reason - type_=cast(Any, MessageContent), + type_=MessageContent, value=merged, ), ) diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index 3476314f7f..b23101ac84 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -2,7 +2,7 @@ import inspect from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, Callable, Iterable, Awaitable, AsyncIterator, cast +from typing import TYPE_CHECKING, Generic, Callable, Iterable, Awaitable, AsyncIterator, cast from typing_extensions import Self, Iterator, assert_never from jiter import from_json @@ -23,7 +23,7 @@ FunctionToolCallArgumentsDeltaEvent, ) from .._deltas import accumulate_delta -from ...._types import Omit, IncEx, omit +from ...._types import Omit, omit from ...._utils import is_given, consume_sync_iterator, consume_async_iterator from ...._compat import model_dump from ...._models import build, construct_type @@ -321,7 +321,9 @@ def __init__( self._input_tools = [tool for tool in input_tools] if is_given(input_tools) else [] self._response_format = response_format - self._rich_response_format: type | Omit = response_format if inspect.isclass(response_format) else omit + self._rich_response_format: type[ResponseFormatT] | Omit = ( + response_format if inspect.isclass(response_format) else omit + ) def get_final_completion(self) -> ParsedChatCompletion[ResponseFormatT]: """Parse the final completion object. @@ -380,17 +382,13 @@ def _accumulate_chunk(self, chunk: ChatCompletionChunk) -> ParsedChatCompletionS # we don't want to serialise / deserialise our custom properties # as they won't appear in the delta and we don't want to have to # continuously reparse the content - exclude=cast( - # cast required as mypy isn't smart enough to infer `True` here to `Literal[True]` - IncEx, - { - "parsed": True, - "tool_calls": { - idx: {"function": {"parsed_arguments": True}} - for idx, _ in enumerate(choice_snapshot.message.tool_calls or []) - }, + exclude={ + "parsed": True, + "tool_calls": { + idx: {"function": {"parsed_arguments": True}} + for idx, _ in enumerate(choice_snapshot.message.tool_calls or []) }, - ), + }, ), ), cast("dict[object, object]", choice.delta.to_dict()), @@ -406,7 +404,7 @@ def _accumulate_chunk(self, chunk: ChatCompletionChunk) -> ParsedChatCompletionS if prev_tool.type == "function": assert new_tool.type == "function" new_tool.function.parsed_arguments = prev_tool.function.parsed_arguments - elif TYPE_CHECKING: # type: ignore[unreachable] + elif TYPE_CHECKING: assert_never(prev_tool) except IndexError: choice_snapshot = cast( @@ -462,7 +460,7 @@ def _accumulate_chunk(self, chunk: ChatCompletionChunk) -> ParsedChatCompletionS bytes(tool_call_snapshot.function.arguments, "utf-8"), partial_mode=True, ) - elif TYPE_CHECKING: # type: ignore[unreachable] + elif TYPE_CHECKING: assert_never(tool_call_snapshot) if choice.logprobs is not None: @@ -551,7 +549,7 @@ def _build_events( arguments_delta=tool_call_delta.function.arguments or "", ) ) - elif TYPE_CHECKING: # type: ignore[unreachable] + elif TYPE_CHECKING: assert_never(tool_call) if choice.logprobs is not None and choice_snapshot.logprobs is not None: @@ -606,7 +604,10 @@ def get_done_events( ) -> list[ChatCompletionStreamEvent[ResponseFormatT]]: events_to_fire: list[ChatCompletionStreamEvent[ResponseFormatT]] = [] - if choice_snapshot.finish_reason: + # In-progress snapshots are constructed from chunks whose finish_reason can be None, + # but ParsedChoiceSnapshot reuses the completed-response type, which excludes None. + # TODO: Model incomplete snapshots separately so their annotations reflect this state. + if choice_snapshot.finish_reason: # ty: ignore[redundant-condition] events_to_fire.extend( self._content_done_events(choice_snapshot=choice_snapshot, response_format=response_format) ) @@ -661,13 +662,7 @@ def _content_done_events( events_to_fire.append( build( - # we do this dance so that when the `ContentDoneEvent` instance - # is printed at runtime the class name will include the solved - # type variable, e.g. `ContentDoneEvent[MyModelType]` - cast( # pyright: ignore[reportUnnecessaryCast] - "type[ContentDoneEvent[ResponseFormatT]]", - cast(Any, ContentDoneEvent), - ), + ContentDoneEvent, type="content.done", content=choice_snapshot.message.content, parsed=parsed, @@ -737,7 +732,7 @@ def _add_tool_done_event( parsed_arguments=parsed_arguments, ) ) - elif TYPE_CHECKING: # type: ignore[unreachable] + elif TYPE_CHECKING: assert_never(tool_call_snapshot) @@ -771,4 +766,4 @@ def _is_valid_chat_completion_chunk_weak(sse_event: ChatCompletionChunk) -> bool # An easy filter is to check for the "object" property: # - should be "chat.completion.chunk" for a ChatCompletionChunk; # - is an empty string for Asynchronous Filter events. - return sse_event.object == "chat.completion.chunk" # type: ignore # pylance reports this as a useless check + return sse_event.object == "chat.completion.chunk" diff --git a/src/openai/lib/streaming/responses/_events.py b/src/openai/lib/streaming/responses/_events.py index 69e106e6de..0980aa46f2 100644 --- a/src/openai/lib/streaming/responses/_events.py +++ b/src/openai/lib/streaming/responses/_events.py @@ -88,7 +88,7 @@ class ResponseFunctionCallArgumentsDeltaEvent(RawResponseFunctionCallArgumentsDe class ResponseCompletedEvent(RawResponseCompletedEvent, GenericModel, Generic[TextFormatT]): - response: ParsedResponse[TextFormatT] # type: ignore[assignment] + response: ParsedResponse[TextFormatT] ResponseStreamEvent: TypeAlias = Annotated[ diff --git a/src/openai/providers/vertex.py b/src/openai/providers/vertex.py index 6a0432f5fc..16de227ce8 100644 --- a/src/openai/providers/vertex.py +++ b/src/openai/providers/vertex.py @@ -65,7 +65,7 @@ def __call__(self, *args: Any, **kwargs: Any) -> Any: # Requests accepts separate connect/read limits, including None. kwargs["timeout"] = (limits.get("connect"), limits.get("read")) try: - return super().__call__(*args, **kwargs) # type: ignore[no-untyped-call] + return super().__call__(*args, **kwargs) except TransportError as exc: if isinstance(exc.__cause__, requests.exceptions.Timeout): raise APITimeoutError(request=request) from None @@ -85,7 +85,7 @@ def __call__(self, *args: Any, **kwargs: Any) -> Any: ) credentials = scope_credentials(self.credentials, scopes=_CLOUD_PLATFORM_SCOPES) headers: dict[str, str] = {} - credentials.before_request(bounded_transport, request.method, str(request.url), headers) # type: ignore[no-untyped-call] + credentials.before_request(bounded_transport, request.method, str(request.url), headers) return headers except (OpenAIError, APITimeoutError): raise diff --git a/src/openai/resources/audio/transcriptions.py b/src/openai/resources/audio/transcriptions.py index c6e829a5e7..ce069c0ce1 100644 --- a/src/openai/resources/audio/transcriptions.py +++ b/src/openai/resources/audio/transcriptions.py @@ -46,7 +46,7 @@ # Retained module entry point; callers may live outside generated resources. -def _get_response_format_type( # pyright: ignore[reportUnusedFunction] +def _get_response_format_type( response_format: AudioResponseFormat | Omit, ) -> type[Transcription | TranscriptionVerbose | TranscriptionDiarized | str]: return openai.lib._parsing._audio.get_transcription_response_format_type(response_format, log=log) diff --git a/src/openai/resources/audio/translations.py b/src/openai/resources/audio/translations.py index b998715827..66c96d9ca7 100644 --- a/src/openai/resources/audio/translations.py +++ b/src/openai/resources/audio/translations.py @@ -33,7 +33,7 @@ # Retained module entry point; callers may live outside generated resources. -def _get_response_format_type( # pyright: ignore[reportUnusedFunction] +def _get_response_format_type( response_format: AudioResponseFormat | Omit, ) -> type[Translation | TranslationVerbose | str]: return openai.lib._parsing._audio.get_translation_response_format_type(response_format, log=log) @@ -419,10 +419,8 @@ class TranslationsWithRawResponse: def __init__(self, translations: Translations) -> None: self._translations = translations - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - translations.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.to_raw_response_wrapper( + translations.create, ) @@ -430,10 +428,8 @@ class AsyncTranslationsWithRawResponse: def __init__(self, translations: AsyncTranslations) -> None: self._translations = translations - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - translations.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.async_to_raw_response_wrapper( + translations.create, ) @@ -441,10 +437,8 @@ class TranslationsWithStreamingResponse: def __init__(self, translations: Translations) -> None: self._translations = translations - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - translations.create, # pyright: ignore[reportDeprecated], - ) + self.create = to_streamed_response_wrapper( + translations.create, ) @@ -452,8 +446,6 @@ class AsyncTranslationsWithStreamingResponse: def __init__(self, translations: AsyncTranslations) -> None: self._translations = translations - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - translations.create, # pyright: ignore[reportDeprecated], - ) + self.create = async_to_streamed_response_wrapper( + translations.create, ) diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index 9a20a474d1..dc3866632c 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -1158,30 +1158,20 @@ class AssistantsWithRawResponse: def __init__(self, assistants: Assistants) -> None: self._assistants = assistants - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - assistants.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.to_raw_response_wrapper( + assistants.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - assistants.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + assistants.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - assistants.update, # pyright: ignore[reportDeprecated], - ) + self.update = _legacy_response.to_raw_response_wrapper( + assistants.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - assistants.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.to_raw_response_wrapper( + assistants.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - assistants.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = _legacy_response.to_raw_response_wrapper( + assistants.delete, ) @@ -1189,30 +1179,20 @@ class AsyncAssistantsWithRawResponse: def __init__(self, assistants: AsyncAssistants) -> None: self._assistants = assistants - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - assistants.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.async_to_raw_response_wrapper( + assistants.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - assistants.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + assistants.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - assistants.update, # pyright: ignore[reportDeprecated], - ) + self.update = _legacy_response.async_to_raw_response_wrapper( + assistants.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - assistants.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.async_to_raw_response_wrapper( + assistants.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - assistants.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + assistants.delete, ) @@ -1220,30 +1200,20 @@ class AssistantsWithStreamingResponse: def __init__(self, assistants: Assistants) -> None: self._assistants = assistants - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - assistants.create, # pyright: ignore[reportDeprecated], - ) + self.create = to_streamed_response_wrapper( + assistants.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - assistants.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = to_streamed_response_wrapper( + assistants.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - assistants.update, # pyright: ignore[reportDeprecated], - ) + self.update = to_streamed_response_wrapper( + assistants.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - assistants.list, # pyright: ignore[reportDeprecated], - ) + self.list = to_streamed_response_wrapper( + assistants.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - assistants.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = to_streamed_response_wrapper( + assistants.delete, ) @@ -1251,28 +1221,18 @@ class AsyncAssistantsWithStreamingResponse: def __init__(self, assistants: AsyncAssistants) -> None: self._assistants = assistants - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - assistants.create, # pyright: ignore[reportDeprecated], - ) + self.create = async_to_streamed_response_wrapper( + assistants.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - assistants.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = async_to_streamed_response_wrapper( + assistants.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - assistants.update, # pyright: ignore[reportDeprecated], - ) + self.update = async_to_streamed_response_wrapper( + assistants.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - assistants.list, # pyright: ignore[reportDeprecated], - ) + self.list = async_to_streamed_response_wrapper( + assistants.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - assistants.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = async_to_streamed_response_wrapper( + assistants.delete, ) diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index 28cd019753..c3d3820783 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -633,30 +633,20 @@ class MessagesWithRawResponse: def __init__(self, messages: Messages) -> None: self._messages = messages - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.to_raw_response_wrapper( + messages.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + messages.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.update, # pyright: ignore[reportDeprecated], - ) + self.update = _legacy_response.to_raw_response_wrapper( + messages.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.to_raw_response_wrapper( + messages.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - messages.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = _legacy_response.to_raw_response_wrapper( + messages.delete, ) @@ -664,30 +654,20 @@ class AsyncMessagesWithRawResponse: def __init__(self, messages: AsyncMessages) -> None: self._messages = messages - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.async_to_raw_response_wrapper( + messages.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + messages.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.update, # pyright: ignore[reportDeprecated], - ) + self.update = _legacy_response.async_to_raw_response_wrapper( + messages.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.async_to_raw_response_wrapper( + messages.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - messages.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + messages.delete, ) @@ -695,30 +675,20 @@ class MessagesWithStreamingResponse: def __init__(self, messages: Messages) -> None: self._messages = messages - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.create, # pyright: ignore[reportDeprecated], - ) + self.create = to_streamed_response_wrapper( + messages.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = to_streamed_response_wrapper( + messages.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.update, # pyright: ignore[reportDeprecated], - ) + self.update = to_streamed_response_wrapper( + messages.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.list, # pyright: ignore[reportDeprecated], - ) + self.list = to_streamed_response_wrapper( + messages.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - messages.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = to_streamed_response_wrapper( + messages.delete, ) @@ -726,28 +696,18 @@ class AsyncMessagesWithStreamingResponse: def __init__(self, messages: AsyncMessages) -> None: self._messages = messages - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.create, # pyright: ignore[reportDeprecated], - ) + self.create = async_to_streamed_response_wrapper( + messages.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = async_to_streamed_response_wrapper( + messages.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.update, # pyright: ignore[reportDeprecated], - ) + self.update = async_to_streamed_response_wrapper( + messages.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.list, # pyright: ignore[reportDeprecated], - ) + self.list = async_to_streamed_response_wrapper( + messages.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - messages.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = async_to_streamed_response_wrapper( + messages.delete, ) diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index a335086034..5834ba5824 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -3161,35 +3161,23 @@ class RunsWithRawResponse: def __init__(self, runs: Runs) -> None: self._runs = runs - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.to_raw_response_wrapper( + runs.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + runs.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.update, # pyright: ignore[reportDeprecated], - ) + self.update = _legacy_response.to_raw_response_wrapper( + runs.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.to_raw_response_wrapper( + runs.list, ) - self.cancel = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.cancel, # pyright: ignore[reportDeprecated], - ) + self.cancel = _legacy_response.to_raw_response_wrapper( + runs.cancel, ) - self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], - ) + self.submit_tool_outputs = _legacy_response.to_raw_response_wrapper( + runs.submit_tool_outputs, ) @cached_property @@ -3202,35 +3190,23 @@ class AsyncRunsWithRawResponse: def __init__(self, runs: AsyncRuns) -> None: self._runs = runs - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.async_to_raw_response_wrapper( + runs.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + runs.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.update, # pyright: ignore[reportDeprecated], - ) + self.update = _legacy_response.async_to_raw_response_wrapper( + runs.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.async_to_raw_response_wrapper( + runs.list, ) - self.cancel = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.cancel, # pyright: ignore[reportDeprecated], - ) + self.cancel = _legacy_response.async_to_raw_response_wrapper( + runs.cancel, ) - self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], - ) + self.submit_tool_outputs = _legacy_response.async_to_raw_response_wrapper( + runs.submit_tool_outputs, ) @cached_property @@ -3243,35 +3219,23 @@ class RunsWithStreamingResponse: def __init__(self, runs: Runs) -> None: self._runs = runs - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.create, # pyright: ignore[reportDeprecated], - ) + self.create = to_streamed_response_wrapper( + runs.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = to_streamed_response_wrapper( + runs.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.update, # pyright: ignore[reportDeprecated], - ) + self.update = to_streamed_response_wrapper( + runs.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.list, # pyright: ignore[reportDeprecated], - ) + self.list = to_streamed_response_wrapper( + runs.list, ) - self.cancel = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.cancel, # pyright: ignore[reportDeprecated], - ) + self.cancel = to_streamed_response_wrapper( + runs.cancel, ) - self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], - ) + self.submit_tool_outputs = to_streamed_response_wrapper( + runs.submit_tool_outputs, ) @cached_property @@ -3284,35 +3248,23 @@ class AsyncRunsWithStreamingResponse: def __init__(self, runs: AsyncRuns) -> None: self._runs = runs - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.create, # pyright: ignore[reportDeprecated], - ) + self.create = async_to_streamed_response_wrapper( + runs.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = async_to_streamed_response_wrapper( + runs.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.update, # pyright: ignore[reportDeprecated], - ) + self.update = async_to_streamed_response_wrapper( + runs.update, ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.list, # pyright: ignore[reportDeprecated], - ) + self.list = async_to_streamed_response_wrapper( + runs.list, ) - self.cancel = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.cancel, # pyright: ignore[reportDeprecated], - ) + self.cancel = async_to_streamed_response_wrapper( + runs.cancel, ) - self.submit_tool_outputs = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - runs.submit_tool_outputs, # pyright: ignore[reportDeprecated], - ) + self.submit_tool_outputs = async_to_streamed_response_wrapper( + runs.submit_tool_outputs, ) @cached_property diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 13f6856765..fabdaafdb8 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -357,15 +357,11 @@ class StepsWithRawResponse: def __init__(self, steps: Steps) -> None: self._steps = steps - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - steps.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + steps.retrieve, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - steps.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.to_raw_response_wrapper( + steps.list, ) @@ -373,15 +369,11 @@ class AsyncStepsWithRawResponse: def __init__(self, steps: AsyncSteps) -> None: self._steps = steps - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - steps.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + steps.retrieve, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - steps.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.async_to_raw_response_wrapper( + steps.list, ) @@ -389,15 +381,11 @@ class StepsWithStreamingResponse: def __init__(self, steps: Steps) -> None: self._steps = steps - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - steps.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = to_streamed_response_wrapper( + steps.retrieve, ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - steps.list, # pyright: ignore[reportDeprecated], - ) + self.list = to_streamed_response_wrapper( + steps.list, ) @@ -405,13 +393,9 @@ class AsyncStepsWithStreamingResponse: def __init__(self, steps: AsyncSteps) -> None: self._steps = steps - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - steps.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = async_to_streamed_response_wrapper( + steps.retrieve, ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - steps.list, # pyright: ignore[reportDeprecated], - ) + self.list = async_to_streamed_response_wrapper( + steps.list, ) diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 3d20a6f572..2694b40649 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -2231,30 +2231,20 @@ class ThreadsWithRawResponse: def __init__(self, threads: Threads) -> None: self._threads = threads - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.to_raw_response_wrapper( + threads.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + threads.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.update, # pyright: ignore[reportDeprecated], - ) + self.update = _legacy_response.to_raw_response_wrapper( + threads.update, ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = _legacy_response.to_raw_response_wrapper( + threads.delete, ) - self.create_and_run = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - threads.create_and_run, # pyright: ignore[reportDeprecated], - ) + self.create_and_run = _legacy_response.to_raw_response_wrapper( + threads.create_and_run, ) @cached_property @@ -2272,30 +2262,20 @@ class AsyncThreadsWithRawResponse: def __init__(self, threads: AsyncThreads) -> None: self._threads = threads - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.async_to_raw_response_wrapper( + threads.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + threads.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.update, # pyright: ignore[reportDeprecated], - ) + self.update = _legacy_response.async_to_raw_response_wrapper( + threads.update, ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + threads.delete, ) - self.create_and_run = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - threads.create_and_run, # pyright: ignore[reportDeprecated], - ) + self.create_and_run = _legacy_response.async_to_raw_response_wrapper( + threads.create_and_run, ) @cached_property @@ -2313,30 +2293,20 @@ class ThreadsWithStreamingResponse: def __init__(self, threads: Threads) -> None: self._threads = threads - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.create, # pyright: ignore[reportDeprecated], - ) + self.create = to_streamed_response_wrapper( + threads.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = to_streamed_response_wrapper( + threads.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.update, # pyright: ignore[reportDeprecated], - ) + self.update = to_streamed_response_wrapper( + threads.update, ) - self.delete = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = to_streamed_response_wrapper( + threads.delete, ) - self.create_and_run = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - threads.create_and_run, # pyright: ignore[reportDeprecated], - ) + self.create_and_run = to_streamed_response_wrapper( + threads.create_and_run, ) @cached_property @@ -2354,30 +2324,20 @@ class AsyncThreadsWithStreamingResponse: def __init__(self, threads: AsyncThreads) -> None: self._threads = threads - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.create, # pyright: ignore[reportDeprecated], - ) + self.create = async_to_streamed_response_wrapper( + threads.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = async_to_streamed_response_wrapper( + threads.retrieve, ) - self.update = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.update, # pyright: ignore[reportDeprecated], - ) + self.update = async_to_streamed_response_wrapper( + threads.update, ) - self.delete = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = async_to_streamed_response_wrapper( + threads.delete, ) - self.create_and_run = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - threads.create_and_run, # pyright: ignore[reportDeprecated], - ) + self.create_and_run = async_to_streamed_response_wrapper( + threads.create_and_run, ) @cached_property diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 963856acec..1d98f6b7ee 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -739,10 +739,8 @@ def __init__(self, files: Files) -> None: self.content = _legacy_response.to_raw_response_wrapper( files.content, ) - self.retrieve_content = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - files.retrieve_content, # pyright: ignore[reportDeprecated], - ) + self.retrieve_content = _legacy_response.to_raw_response_wrapper( + files.retrieve_content, ) @@ -765,10 +763,8 @@ def __init__(self, files: AsyncFiles) -> None: self.content = _legacy_response.async_to_raw_response_wrapper( files.content, ) - self.retrieve_content = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - files.retrieve_content, # pyright: ignore[reportDeprecated], - ) + self.retrieve_content = _legacy_response.async_to_raw_response_wrapper( + files.retrieve_content, ) @@ -792,10 +788,8 @@ def __init__(self, files: Files) -> None: files.content, StreamedBinaryAPIResponse, ) - self.retrieve_content = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - files.retrieve_content, # pyright: ignore[reportDeprecated], - ) + self.retrieve_content = to_streamed_response_wrapper( + files.retrieve_content, ) @@ -819,8 +813,6 @@ def __init__(self, files: AsyncFiles) -> None: files.content, AsyncStreamedBinaryAPIResponse, ) - self.retrieve_content = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - files.retrieve_content, # pyright: ignore[reportDeprecated], - ) + self.retrieve_content = async_to_streamed_response_wrapper( + files.retrieve_content, ) diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index 7d2136f4db..e7f35704f7 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -557,10 +557,8 @@ def __init__(self, permissions: Permissions) -> None: self.create = _legacy_response.to_raw_response_wrapper( permissions.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - permissions.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + permissions.retrieve, ) self.list = _legacy_response.to_raw_response_wrapper( permissions.list, @@ -577,10 +575,8 @@ def __init__(self, permissions: AsyncPermissions) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( permissions.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - permissions.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + permissions.retrieve, ) self.list = _legacy_response.async_to_raw_response_wrapper( permissions.list, @@ -597,10 +593,8 @@ def __init__(self, permissions: Permissions) -> None: self.create = to_streamed_response_wrapper( permissions.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - permissions.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = to_streamed_response_wrapper( + permissions.retrieve, ) self.list = to_streamed_response_wrapper( permissions.list, @@ -617,10 +611,8 @@ def __init__(self, permissions: AsyncPermissions) -> None: self.create = async_to_streamed_response_wrapper( permissions.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - permissions.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = async_to_streamed_response_wrapper( + permissions.retrieve, ) self.list = async_to_streamed_response_wrapper( permissions.list, diff --git a/src/openai/resources/images.py b/src/openai/resources/images.py index 384e2aed33..e9442df1ff 100644 --- a/src/openai/resources/images.py +++ b/src/openai/resources/images.py @@ -2344,10 +2344,8 @@ class ImagesWithRawResponse: def __init__(self, images: Images) -> None: self._images = images - self.create_variation = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - images.create_variation, # pyright: ignore[reportDeprecated], - ) + self.create_variation = _legacy_response.to_raw_response_wrapper( + images.create_variation, ) self.edit = _legacy_response.to_raw_response_wrapper( images.edit, @@ -2361,10 +2359,8 @@ class AsyncImagesWithRawResponse: def __init__(self, images: AsyncImages) -> None: self._images = images - self.create_variation = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - images.create_variation, # pyright: ignore[reportDeprecated], - ) + self.create_variation = _legacy_response.async_to_raw_response_wrapper( + images.create_variation, ) self.edit = _legacy_response.async_to_raw_response_wrapper( images.edit, @@ -2378,10 +2374,8 @@ class ImagesWithStreamingResponse: def __init__(self, images: Images) -> None: self._images = images - self.create_variation = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - images.create_variation, # pyright: ignore[reportDeprecated], - ) + self.create_variation = to_streamed_response_wrapper( + images.create_variation, ) self.edit = to_streamed_response_wrapper( images.edit, @@ -2395,10 +2389,8 @@ class AsyncImagesWithStreamingResponse: def __init__(self, images: AsyncImages) -> None: self._images = images - self.create_variation = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - images.create_variation, # pyright: ignore[reportDeprecated], - ) + self.create_variation = async_to_streamed_response_wrapper( + images.create_variation, ) self.edit = async_to_streamed_response_wrapper( images.edit, diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index 9213e23e24..e3f4ba1db4 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -577,7 +577,7 @@ def create_and_poll( timeout: float | httpx2.Timeout | None | NotGiven = not_given, ) -> Video: "Create a video and wait for it to be processed." - video = self.create( # pyright: ignore[reportDeprecated] + video = self.create( model=model, prompt=prompt, input_reference=input_reference, @@ -589,7 +589,7 @@ def create_and_poll( timeout=timeout, ) - return self.poll( # pyright: ignore[reportDeprecated] + return self.poll( video.id, poll_interval_ms=poll_interval_ms, ) @@ -607,7 +607,7 @@ def poll( headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) while True: - response = self.with_raw_response.retrieve( # pyright: ignore[reportDeprecated] + response = self.with_raw_response.retrieve( video_id, extra_headers=headers, ) @@ -625,7 +625,7 @@ def poll( elif video.status == "completed" or video.status == "failed": return video else: - if TYPE_CHECKING: # type: ignore[unreachable] + if TYPE_CHECKING: assert_never(video.status) else: return video @@ -1164,7 +1164,7 @@ async def create_and_poll( timeout: float | httpx2.Timeout | None | NotGiven = not_given, ) -> Video: "Create a video and wait for it to be processed." - video = await self.create( # pyright: ignore[reportDeprecated] + video = await self.create( model=model, prompt=prompt, input_reference=input_reference, @@ -1176,7 +1176,7 @@ async def create_and_poll( timeout=timeout, ) - return await self.poll( # pyright: ignore[reportDeprecated] + return await self.poll( video.id, poll_interval_ms=poll_interval_ms, ) @@ -1194,7 +1194,7 @@ async def poll( headers["X-Stainless-Custom-Poll-Interval"] = str(poll_interval_ms) while True: - response = await self.with_raw_response.retrieve( # pyright: ignore[reportDeprecated] + response = await self.with_raw_response.retrieve( video_id, extra_headers=headers, ) @@ -1212,7 +1212,7 @@ async def poll( elif video.status == "completed" or video.status == "failed": return video else: - if TYPE_CHECKING: # type: ignore[unreachable] + if TYPE_CHECKING: assert_never(video.status) else: return video @@ -1222,55 +1222,35 @@ class VideosWithRawResponse: def __init__(self, videos: Videos) -> None: self._videos = videos - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.to_raw_response_wrapper( + videos.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + videos.retrieve, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.to_raw_response_wrapper( + videos.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = _legacy_response.to_raw_response_wrapper( + videos.delete, ) - self.create_character = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.create_character, # pyright: ignore[reportDeprecated], - ) + self.create_character = _legacy_response.to_raw_response_wrapper( + videos.create_character, ) - self.download_content = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.download_content, # pyright: ignore[reportDeprecated], - ) + self.download_content = _legacy_response.to_raw_response_wrapper( + videos.download_content, ) - self.edit = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.edit, # pyright: ignore[reportDeprecated], - ) + self.edit = _legacy_response.to_raw_response_wrapper( + videos.edit, ) - self.extend = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.extend, # pyright: ignore[reportDeprecated], - ) + self.extend = _legacy_response.to_raw_response_wrapper( + videos.extend, ) - self.get_character = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.get_character, # pyright: ignore[reportDeprecated], - ) + self.get_character = _legacy_response.to_raw_response_wrapper( + videos.get_character, ) - self.remix = ( # pyright: ignore[reportDeprecated] - _legacy_response.to_raw_response_wrapper( - videos.remix, # pyright: ignore[reportDeprecated], - ) + self.remix = _legacy_response.to_raw_response_wrapper( + videos.remix, ) @@ -1278,55 +1258,35 @@ class AsyncVideosWithRawResponse: def __init__(self, videos: AsyncVideos) -> None: self._videos = videos - self.create = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.create, # pyright: ignore[reportDeprecated], - ) + self.create = _legacy_response.async_to_raw_response_wrapper( + videos.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + videos.retrieve, ) - self.list = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.list, # pyright: ignore[reportDeprecated], - ) + self.list = _legacy_response.async_to_raw_response_wrapper( + videos.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + videos.delete, ) - self.create_character = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.create_character, # pyright: ignore[reportDeprecated], - ) + self.create_character = _legacy_response.async_to_raw_response_wrapper( + videos.create_character, ) - self.download_content = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.download_content, # pyright: ignore[reportDeprecated], - ) + self.download_content = _legacy_response.async_to_raw_response_wrapper( + videos.download_content, ) - self.edit = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.edit, # pyright: ignore[reportDeprecated], - ) + self.edit = _legacy_response.async_to_raw_response_wrapper( + videos.edit, ) - self.extend = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.extend, # pyright: ignore[reportDeprecated], - ) + self.extend = _legacy_response.async_to_raw_response_wrapper( + videos.extend, ) - self.get_character = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.get_character, # pyright: ignore[reportDeprecated], - ) + self.get_character = _legacy_response.async_to_raw_response_wrapper( + videos.get_character, ) - self.remix = ( # pyright: ignore[reportDeprecated] - _legacy_response.async_to_raw_response_wrapper( - videos.remix, # pyright: ignore[reportDeprecated], - ) + self.remix = _legacy_response.async_to_raw_response_wrapper( + videos.remix, ) @@ -1334,56 +1294,36 @@ class VideosWithStreamingResponse: def __init__(self, videos: Videos) -> None: self._videos = videos - self.create = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.create, # pyright: ignore[reportDeprecated], - ) + self.create = to_streamed_response_wrapper( + videos.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = to_streamed_response_wrapper( + videos.retrieve, ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.list, # pyright: ignore[reportDeprecated], - ) + self.list = to_streamed_response_wrapper( + videos.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = to_streamed_response_wrapper( + videos.delete, ) - self.create_character = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.create_character, # pyright: ignore[reportDeprecated], - ) + self.create_character = to_streamed_response_wrapper( + videos.create_character, ) - self.download_content = ( # pyright: ignore[reportDeprecated] - to_custom_streamed_response_wrapper( - videos.download_content, # pyright: ignore[reportDeprecated], - StreamedBinaryAPIResponse, - ) + self.download_content = to_custom_streamed_response_wrapper( + videos.download_content, + StreamedBinaryAPIResponse, ) - self.edit = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.edit, # pyright: ignore[reportDeprecated], - ) + self.edit = to_streamed_response_wrapper( + videos.edit, ) - self.extend = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.extend, # pyright: ignore[reportDeprecated], - ) + self.extend = to_streamed_response_wrapper( + videos.extend, ) - self.get_character = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.get_character, # pyright: ignore[reportDeprecated], - ) + self.get_character = to_streamed_response_wrapper( + videos.get_character, ) - self.remix = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - videos.remix, # pyright: ignore[reportDeprecated], - ) + self.remix = to_streamed_response_wrapper( + videos.remix, ) @@ -1391,54 +1331,34 @@ class AsyncVideosWithStreamingResponse: def __init__(self, videos: AsyncVideos) -> None: self._videos = videos - self.create = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.create, # pyright: ignore[reportDeprecated], - ) + self.create = async_to_streamed_response_wrapper( + videos.create, ) - self.retrieve = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.retrieve, # pyright: ignore[reportDeprecated], - ) + self.retrieve = async_to_streamed_response_wrapper( + videos.retrieve, ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.list, # pyright: ignore[reportDeprecated], - ) + self.list = async_to_streamed_response_wrapper( + videos.list, ) - self.delete = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.delete, # pyright: ignore[reportDeprecated], - ) + self.delete = async_to_streamed_response_wrapper( + videos.delete, ) - self.create_character = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.create_character, # pyright: ignore[reportDeprecated], - ) + self.create_character = async_to_streamed_response_wrapper( + videos.create_character, ) - self.download_content = ( # pyright: ignore[reportDeprecated] - async_to_custom_streamed_response_wrapper( - videos.download_content, # pyright: ignore[reportDeprecated], - AsyncStreamedBinaryAPIResponse, - ) + self.download_content = async_to_custom_streamed_response_wrapper( + videos.download_content, + AsyncStreamedBinaryAPIResponse, ) - self.edit = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.edit, # pyright: ignore[reportDeprecated], - ) + self.edit = async_to_streamed_response_wrapper( + videos.edit, ) - self.extend = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.extend, # pyright: ignore[reportDeprecated], - ) + self.extend = async_to_streamed_response_wrapper( + videos.extend, ) - self.get_character = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.get_character, # pyright: ignore[reportDeprecated], - ) + self.get_character = async_to_streamed_response_wrapper( + videos.get_character, ) - self.remix = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - videos.remix, # pyright: ignore[reportDeprecated], - ) + self.remix = async_to_streamed_response_wrapper( + videos.remix, ) diff --git a/src/openai/types/beta/beta_response_custom_tool_call_item.py b/src/openai/types/beta/beta_response_custom_tool_call_item.py index 9509ee3828..1bc0abc092 100644 --- a/src/openai/types/beta/beta_response_custom_tool_call_item.py +++ b/src/openai/types/beta/beta_response_custom_tool_call_item.py @@ -11,7 +11,7 @@ class BetaResponseCustomToolCallItem(BetaResponseCustomToolCall): """A call to a custom tool created by the model.""" - id: str # type: ignore + id: str # ty: ignore[invalid-mutable-override] """The unique ID of the custom tool call item.""" status: Literal["in_progress", "completed", "incomplete"] diff --git a/src/openai/types/beta/beta_response_custom_tool_call_output_item.py b/src/openai/types/beta/beta_response_custom_tool_call_output_item.py index fe1cd96e30..2f3470a1d8 100644 --- a/src/openai/types/beta/beta_response_custom_tool_call_output_item.py +++ b/src/openai/types/beta/beta_response_custom_tool_call_output_item.py @@ -11,7 +11,7 @@ class BetaResponseCustomToolCallOutputItem(BetaResponseCustomToolCallOutput): """The output of a custom tool call from your code, being sent back to the model.""" - id: str # type: ignore + id: str # ty: ignore[invalid-mutable-override] """The unique ID of the custom tool call output item.""" status: Literal["in_progress", "completed", "incomplete"] diff --git a/src/openai/types/beta/beta_response_function_tool_call_item.py b/src/openai/types/beta/beta_response_function_tool_call_item.py index 0c1658325e..7536973a0a 100644 --- a/src/openai/types/beta/beta_response_function_tool_call_item.py +++ b/src/openai/types/beta/beta_response_function_tool_call_item.py @@ -15,10 +15,10 @@ class BetaResponseFunctionToolCallItem(BetaResponseFunctionToolCall): [function calling guide](https://developers.openai.com/api/docs/guides/function-calling) for more information. """ - id: str # type: ignore + id: str # ty: ignore[invalid-mutable-override] """The unique ID of the function tool call.""" - status: Literal["in_progress", "completed", "incomplete"] # type: ignore + status: Literal["in_progress", "completed", "incomplete"] # ty: ignore[invalid-mutable-override] """The status of the item. One of `in_progress`, `completed`, or `incomplete`. Populated when items are diff --git a/src/openai/types/chat/parsed_chat_completion.py b/src/openai/types/chat/parsed_chat_completion.py index ba7dc78d21..ba7c36bc9c 100644 --- a/src/openai/types/chat/parsed_chat_completion.py +++ b/src/openai/types/chat/parsed_chat_completion.py @@ -14,14 +14,13 @@ # we need to disable this check because we're overriding properties # with subclasses of their types which is technically unsound as # properties can be mutated. -# pyright: reportIncompatibleVariableOverride=false class ParsedChatCompletionMessage(ChatCompletionMessage, GenericModel, Generic[ContentType]): parsed: Optional[ContentType] = None """The auto-parsed message contents""" - tool_calls: Optional[List[ParsedFunctionToolCall]] = None # type: ignore[assignment] + tool_calls: Optional[List[ParsedFunctionToolCall]] = None # ty: ignore[invalid-attribute-override] """The tool calls generated by the model, such as function calls.""" @@ -31,7 +30,7 @@ class ParsedChoice(Choice, GenericModel, Generic[ContentType]): class ParsedChatCompletion(ChatCompletion, GenericModel, Generic[ContentType]): - choices: List[ParsedChoice[ContentType]] # type: ignore[assignment] + choices: List[ParsedChoice[ContentType]] # ty: ignore[invalid-attribute-override] """A list of chat completion choices. Can be more than one if `n` is greater than 1. diff --git a/src/openai/types/chat/parsed_function_tool_call.py b/src/openai/types/chat/parsed_function_tool_call.py index 9c31b0f627..3af62e4ca2 100644 --- a/src/openai/types/chat/parsed_function_tool_call.py +++ b/src/openai/types/chat/parsed_function_tool_call.py @@ -7,7 +7,6 @@ # we need to disable this check because we're overriding properties # with subclasses of their types which is technically unsound as # properties can be mutated. -# pyright: reportIncompatibleVariableOverride=false class ParsedFunction(Function): diff --git a/src/openai/types/evals/runs/output_item_list_response.py b/src/openai/types/evals/runs/output_item_list_response.py index 5db0f34570..c9c2d78b95 100644 --- a/src/openai/types/evals/runs/output_item_list_response.py +++ b/src/openai/types/evals/runs/output_item_list_response.py @@ -32,7 +32,7 @@ class Result(BaseModel): if TYPE_CHECKING: # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a # value to this field, so for compatibility we avoid doing it at runtime. - __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # Stub to indicate that arbitrary properties are accepted. # To access properties that are not valid identifiers you can use `getattr`, e.g. diff --git a/src/openai/types/evals/runs/output_item_retrieve_response.py b/src/openai/types/evals/runs/output_item_retrieve_response.py index 096ff4d013..5634783007 100644 --- a/src/openai/types/evals/runs/output_item_retrieve_response.py +++ b/src/openai/types/evals/runs/output_item_retrieve_response.py @@ -32,7 +32,7 @@ class Result(BaseModel): if TYPE_CHECKING: # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a # value to this field, so for compatibility we avoid doing it at runtime. - __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # Stub to indicate that arbitrary properties are accepted. # To access properties that are not valid identifiers you can use `getattr`, e.g. diff --git a/src/openai/types/responses/parsed_response.py b/src/openai/types/responses/parsed_response.py index d0977fa23a..785578500c 100644 --- a/src/openai/types/responses/parsed_response.py +++ b/src/openai/types/responses/parsed_response.py @@ -45,7 +45,6 @@ # we need to disable this check because we're overriding properties # with subclasses of their types which is technically unsound as # properties can be mutated. -# pyright: reportIncompatibleVariableOverride=false class ParsedResponseOutputText(ResponseOutputText, GenericModel, Generic[ContentType]): @@ -60,7 +59,7 @@ class ParsedResponseOutputText(ResponseOutputText, GenericModel, Generic[Content class ParsedResponseOutputMessage(ResponseOutputMessage, GenericModel, Generic[ContentType]): if TYPE_CHECKING: - content: List[ParsedContent[ContentType]] # type: ignore[assignment] + content: List[ParsedContent[ContentType]] # ty: ignore[invalid-attribute-override] else: content: List[ParsedContent] @@ -109,7 +108,7 @@ class ParsedResponseFunctionToolCall(ResponseFunctionToolCall): class ParsedResponse(Response, GenericModel, Generic[ContentType]): if TYPE_CHECKING: - output: List[ParsedResponseOutputItem[ContentType]] # type: ignore[assignment] + output: List[ParsedResponseOutputItem[ContentType]] # ty: ignore[invalid-attribute-override] else: output: List[ParsedResponseOutputItem] diff --git a/src/openai/types/responses/response_custom_tool_call_item.py b/src/openai/types/responses/response_custom_tool_call_item.py index f933761c9a..e81646b870 100644 --- a/src/openai/types/responses/response_custom_tool_call_item.py +++ b/src/openai/types/responses/response_custom_tool_call_item.py @@ -11,7 +11,7 @@ class ResponseCustomToolCallItem(ResponseCustomToolCall): """A call to a custom tool created by the model.""" - id: str # type: ignore + id: str # ty: ignore[invalid-mutable-override] """The unique ID of the custom tool call item.""" status: Literal["in_progress", "completed", "incomplete"] diff --git a/src/openai/types/responses/response_custom_tool_call_output_item.py b/src/openai/types/responses/response_custom_tool_call_output_item.py index d54cadadf8..0f11cbc1d4 100644 --- a/src/openai/types/responses/response_custom_tool_call_output_item.py +++ b/src/openai/types/responses/response_custom_tool_call_output_item.py @@ -11,7 +11,7 @@ class ResponseCustomToolCallOutputItem(ResponseCustomToolCallOutput): """The output of a custom tool call from your code, being sent back to the model.""" - id: str # type: ignore + id: str # ty: ignore[invalid-mutable-override] """The unique ID of the custom tool call output item.""" status: Literal["in_progress", "completed", "incomplete"] diff --git a/src/openai/types/responses/response_function_tool_call_item.py b/src/openai/types/responses/response_function_tool_call_item.py index fa0137666a..f39980465e 100644 --- a/src/openai/types/responses/response_function_tool_call_item.py +++ b/src/openai/types/responses/response_function_tool_call_item.py @@ -15,10 +15,10 @@ class ResponseFunctionToolCallItem(ResponseFunctionToolCall): [function calling guide](https://developers.openai.com/api/docs/guides/function-calling) for more information. """ - id: str # type: ignore + id: str # ty: ignore[invalid-mutable-override] """The unique ID of the function tool call.""" - status: Literal["in_progress", "completed", "incomplete"] # type: ignore + status: Literal["in_progress", "completed", "incomplete"] # ty: ignore[invalid-mutable-override] """The status of the item. One of `in_progress`, `completed`, or `incomplete`. Populated when items are diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index 57985851e8..2dbcf1dce7 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -13,8 +13,6 @@ from tests.utils import assert_matches_type from tests.respx2 import MockRouter -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/audio/test_transcriptions.py b/tests/api_resources/audio/test_transcriptions.py index c1fec352b3..55c634669f 100644 --- a/tests/api_resources/audio/test_transcriptions.py +++ b/tests/api_resources/audio/test_transcriptions.py @@ -7,7 +7,7 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.types.audio import TranscriptionCreateResponse @@ -110,6 +110,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -123,6 +124,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -226,6 +228,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -239,6 +242,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/audio/test_translations.py b/tests/api_resources/audio/test_translations.py index e9eba53660..5a756eab1b 100644 --- a/tests/api_resources/audio/test_translations.py +++ b/tests/api_resources/audio/test_translations.py @@ -11,8 +11,6 @@ from tests.utils import assert_matches_type from openai.types.audio import TranslationCreateResponse -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/beta/agents/sessions/test_artifacts.py b/tests/api_resources/beta/agents/sessions/test_artifacts.py index 0e78e3327b..c74bbb3db6 100644 --- a/tests/api_resources/beta/agents/sessions/test_artifacts.py +++ b/tests/api_resources/beta/agents/sessions/test_artifacts.py @@ -18,8 +18,6 @@ SessionArtifactDeleted, ) -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/beta/agents/sessions/test_events.py b/tests/api_resources/beta/agents/sessions/test_events.py index 057dffe623..5edb14435c 100644 --- a/tests/api_resources/beta/agents/sessions/test_events.py +++ b/tests/api_resources/beta/agents/sessions/test_events.py @@ -7,7 +7,7 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -157,6 +157,7 @@ def test_raw_response_stream(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -168,6 +169,7 @@ def test_streaming_response_stream(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -327,6 +329,7 @@ async def test_raw_response_stream(self, async_client: AsyncOpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -338,6 +341,7 @@ async def test_streaming_response_stream(self, async_client: AsyncOpenAI) -> Non assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/beta/agents/test_sessions.py b/tests/api_resources/beta/agents/test_sessions.py index 84455a3c04..0e87d898d2 100644 --- a/tests/api_resources/beta/agents/test_sessions.py +++ b/tests/api_resources/beta/agents/test_sessions.py @@ -7,7 +7,7 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.beta import AgentSession, AgentSessionDeleted @@ -144,6 +144,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -156,6 +157,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -456,6 +458,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -468,6 +471,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index d88f9e154e..b5b32a9f2e 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -15,8 +15,6 @@ AssistantDeleted, ) -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/beta/test_realtime.py b/tests/api_resources/beta/test_realtime.py index 96146dfa51..0c5b50aa2b 100644 --- a/tests/api_resources/beta/test_realtime.py +++ b/tests/api_resources/beta/test_realtime.py @@ -4,8 +4,6 @@ import pytest -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/beta/test_responses.py b/tests/api_resources/beta/test_responses.py index 51b9d1649e..9b8431b222 100644 --- a/tests/api_resources/beta/test_responses.py +++ b/tests/api_resources/beta/test_responses.py @@ -7,7 +7,7 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.types.beta import ( BetaResponse, @@ -228,6 +228,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -239,6 +240,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -322,6 +324,7 @@ def test_raw_response_retrieve_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -334,6 +337,7 @@ def test_streaming_response_retrieve_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -701,6 +705,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -712,6 +717,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True @@ -795,6 +801,7 @@ async def test_raw_response_retrieve_overload_2(self, async_client: AsyncOpenAI) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -807,6 +814,7 @@ async def test_streaming_response_retrieve_overload_2(self, async_client: AsyncO assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/beta/test_threads.py b/tests/api_resources/beta/test_threads.py index fd850f2afc..23aab357b6 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -7,7 +7,7 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.types.beta import ( Thread, @@ -15,8 +15,6 @@ ) from openai.types.beta.threads import Run -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -401,6 +399,7 @@ def test_raw_response_create_and_run_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -414,6 +413,7 @@ def test_streaming_response_create_and_run_overload_2(self, client: OpenAI) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -802,6 +802,7 @@ async def test_raw_response_create_and_run_overload_2(self, async_client: AsyncO assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -815,6 +816,7 @@ async def test_streaming_response_create_and_run_overload_2(self, async_client: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/beta/threads/runs/test_steps.py b/tests/api_resources/beta/threads/runs/test_steps.py index 8095417753..53e86204b4 100644 --- a/tests/api_resources/beta/threads/runs/test_steps.py +++ b/tests/api_resources/beta/threads/runs/test_steps.py @@ -12,8 +12,6 @@ from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.beta.threads.runs import RunStep -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/beta/threads/test_messages.py b/tests/api_resources/beta/threads/test_messages.py index 4f7804f3f8..834a7f7032 100644 --- a/tests/api_resources/beta/threads/test_messages.py +++ b/tests/api_resources/beta/threads/test_messages.py @@ -15,8 +15,6 @@ MessageDeleted, ) -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/beta/threads/test_runs.py b/tests/api_resources/beta/threads/test_runs.py index 390b844a1d..a6ba2a2c8e 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -7,15 +7,13 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.beta.threads import ( Run, ) -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -175,6 +173,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -189,6 +188,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -528,6 +528,7 @@ def test_raw_response_submit_tool_outputs_overload_2(self, client: OpenAI) -> No assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -543,6 +544,7 @@ def test_streaming_response_submit_tool_outputs_overload_2(self, client: OpenAI) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -725,6 +727,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -739,6 +742,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True @@ -1078,6 +1082,7 @@ async def test_raw_response_submit_tool_outputs_overload_2(self, async_client: A assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -1093,6 +1098,7 @@ async def test_streaming_response_submit_tool_outputs_overload_2(self, async_cli assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py index d21835400d..2e462a8e5c 100644 --- a/tests/api_resources/chat/test_completions.py +++ b/tests/api_resources/chat/test_completions.py @@ -7,7 +7,7 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.chat import ( @@ -287,6 +287,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -305,6 +306,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -735,6 +737,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -753,6 +756,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/containers/files/test_content.py b/tests/api_resources/containers/files/test_content.py index b71577f8a8..6c6c2f9841 100644 --- a/tests/api_resources/containers/files/test_content.py +++ b/tests/api_resources/containers/files/test_content.py @@ -13,8 +13,6 @@ from tests.utils import assert_matches_type from tests.respx2 import MockRouter -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py index 0b6f39bb14..f44643de35 100644 --- a/tests/api_resources/fine_tuning/checkpoints/test_permissions.py +++ b/tests/api_resources/fine_tuning/checkpoints/test_permissions.py @@ -17,8 +17,6 @@ PermissionRetrieveResponse, ) -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/live/test_sessions.py b/tests/api_resources/live/test_sessions.py index 2e69d6fe3c..5ac33a027d 100644 --- a/tests/api_resources/live/test_sessions.py +++ b/tests/api_resources/live/test_sessions.py @@ -16,8 +16,6 @@ SessionForkResponse, ) -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/realtime/test_calls.py b/tests/api_resources/realtime/test_calls.py index cd5466917c..f4f413bd7c 100644 --- a/tests/api_resources/realtime/test_calls.py +++ b/tests/api_resources/realtime/test_calls.py @@ -13,8 +13,6 @@ from tests.utils import assert_matches_type from tests.respx2 import MockRouter -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/skills/test_content.py b/tests/api_resources/skills/test_content.py index 04d1d0c67a..a3bdd110d8 100644 --- a/tests/api_resources/skills/test_content.py +++ b/tests/api_resources/skills/test_content.py @@ -13,8 +13,6 @@ from tests.utils import assert_matches_type from tests.respx2 import MockRouter -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/skills/versions/test_content.py b/tests/api_resources/skills/versions/test_content.py index 2c0b453c6b..cae46227cb 100644 --- a/tests/api_resources/skills/versions/test_content.py +++ b/tests/api_resources/skills/versions/test_content.py @@ -13,8 +13,6 @@ from tests.utils import assert_matches_type from tests.respx2 import MockRouter -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/test_completions.py b/tests/api_resources/test_completions.py index f8cfb685e9..32a9d0b848 100644 --- a/tests/api_resources/test_completions.py +++ b/tests/api_resources/test_completions.py @@ -7,7 +7,7 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.types import Completion @@ -124,6 +124,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -137,6 +138,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -254,6 +256,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -267,6 +270,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index deb0e3aa61..498b43ff97 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -15,8 +15,6 @@ from tests.respx2 import MockRouter from openai.pagination import SyncCursorPage, AsyncCursorPage -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index d24d308453..8c7d4001de 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -7,12 +7,10 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.types import ImagesResponse -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -165,6 +163,7 @@ def test_raw_response_edit_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -178,6 +177,7 @@ def test_streaming_response_edit_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -272,6 +272,7 @@ def test_raw_response_generate_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -284,6 +285,7 @@ def test_streaming_response_generate_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -440,6 +442,7 @@ async def test_raw_response_edit_overload_2(self, async_client: AsyncOpenAI) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -453,6 +456,7 @@ async def test_streaming_response_edit_overload_2(self, async_client: AsyncOpenA assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True @@ -547,6 +551,7 @@ async def test_raw_response_generate_overload_2(self, async_client: AsyncOpenAI) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -559,6 +564,7 @@ async def test_streaming_response_generate_overload_2(self, async_client: AsyncO assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index 08acf69719..7b0383b3d3 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -7,7 +7,7 @@ import pytest -from openai import OpenAI, AsyncOpenAI +from openai import OpenAI, Stream as _Stream, AsyncOpenAI, AsyncStream as _AsyncStream from tests.utils import assert_matches_type from openai.types.responses import ( Response, @@ -218,6 +218,7 @@ def test_raw_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -229,6 +230,7 @@ def test_streaming_response_create_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -310,6 +312,7 @@ def test_raw_response_retrieve_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() @parametrize @@ -322,6 +325,7 @@ def test_streaming_response_retrieve_overload_2(self, client: OpenAI) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _Stream) stream.close() assert cast(Any, response.is_closed) is True @@ -662,6 +666,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncOpenAI) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -673,6 +678,7 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncOpe assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True @@ -754,6 +760,7 @@ async def test_raw_response_retrieve_overload_2(self, async_client: AsyncOpenAI) assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() @parametrize @@ -766,6 +773,7 @@ async def test_streaming_response_retrieve_overload_2(self, async_client: AsyncO assert response.http_request.headers.get("X-Stainless-Lang") == "python" stream = await response.parse() + assert isinstance(stream, _AsyncStream) await stream.close() assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_videos.py b/tests/api_resources/test_videos.py index d93932c978..7c89dddc3c 100644 --- a/tests/api_resources/test_videos.py +++ b/tests/api_resources/test_videos.py @@ -21,8 +21,6 @@ from openai._utils import assert_signatures_in_sync from openai.pagination import SyncConversationCursorPage, AsyncConversationCursorPage -# pyright: reportDeprecated=false - base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -933,7 +931,7 @@ def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client checking_client: OpenAI | AsyncOpenAI = client if sync else async_client assert_signatures_in_sync( - checking_client.videos.create, # pyright: ignore[reportDeprecated] - checking_client.videos.create_and_poll, # pyright: ignore[reportDeprecated] + checking_client.videos.create, + checking_client.videos.create_and_poll, exclude_params={"extra_headers", "extra_query", "extra_body", "timeout"}, ) diff --git a/tests/conftest.py b/tests/conftest.py index c02deeae23..218aae30f4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,7 +12,7 @@ from openai._utils import is_dict if TYPE_CHECKING: - from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] + from _pytest.fixtures import FixtureRequest pytest_plugins = ["tests.respx2.plugin"] diff --git a/tests/lib/bedrock_live.py b/tests/lib/bedrock_live.py index f05ddd8c5a..f48c34714c 100644 --- a/tests/lib/bedrock_live.py +++ b/tests/lib/bedrock_live.py @@ -18,7 +18,7 @@ import os import re -from typing import Literal, cast +from typing import Literal from pathlib import Path from openai import OpenAI @@ -118,7 +118,7 @@ def test_bedrock_live_response() -> None: configured_endpoint = os.environ.get("BEDROCK_LIVE_ENDPOINT", "mantle") if configured_endpoint not in {"mantle", "runtime"}: raise RuntimeError("BEDROCK_LIVE_ENDPOINT must be 'mantle' or 'runtime'.") - endpoint = cast("Literal['mantle', 'runtime']", configured_endpoint) + endpoint = configured_endpoint region = os.environ.get("BEDROCK_LIVE_REGION") or None base_url = os.environ.get("AWS_BEDROCK_BASE_URL") or None if endpoint == "mantle" and base_url is None: @@ -155,7 +155,8 @@ def test_bedrock_live_response() -> None: messages=[{"role": "user", "content": "Reply with exactly: bedrock live test ok"}], ) assert completion.choices[0].message.content - assert completion.choices[0].finish_reason + # Check the actual service payload rather than assuming its annotation is valid. + assert completion.choices[0].finish_reason # ty: ignore[redundant-condition] assert completion.usage is not None print(f"Bedrock Runtime {authentication} chat {completion.id}: {model}") diff --git a/tests/lib/beta/agents/test_tools.py b/tests/lib/beta/agents/test_tools.py index 394d2868e5..b405d75efa 100644 --- a/tests/lib/beta/agents/test_tools.py +++ b/tests/lib/beta/agents/test_tools.py @@ -45,8 +45,9 @@ def test_bound_action_schema_defaults_and_nested_models() -> None: assert tool.name == "reserve" assert tool.definition["type"] == "function" assert tool.definition["description"] == "Reserve an item from this catalog." - assert set(tool.definition["parameters"]["properties"]) == {"item", "quantity", "product"} # type: ignore - assert "self" not in tool.definition["parameters"]["properties"] # type: ignore + # JSON-schema values are typed as object; these assertions verify the generated structure. + assert set(tool.definition["parameters"]["properties"]) == {"item", "quantity", "product"} # ty: ignore[invalid-argument-type] + assert "self" not in tool.definition["parameters"]["properties"] # ty: ignore[unsupported-operator] assert json.loads(cast(str, tool({"item": {"sku": "test-sku"}, "quantity": 3}))) == { "receipt": "test-receipt", "product": "notebook", @@ -81,7 +82,8 @@ def handler(arguments: Arguments) -> str: tool = pydantic_function_tool(Arguments, name="reserve", description="Reserve items", handler=handler) assert tool({"quantity_units": 2}) == "2" assert isinstance(seen[0], Arguments) - assert "quantity_units" in tool.definition["parameters"]["properties"] # type: ignore + # The schema keeps dynamic JSON values rather than a fixed properties mapping. + assert "quantity_units" in tool.definition["parameters"]["properties"] # ty: ignore[unsupported-operator] with pytest.raises(ValidationError): tool({"quantity_units": 0}) assert len(seen) == 1 @@ -125,11 +127,11 @@ async def test_bound_action_through_existing_dispatch(asynchronous: bool, invali transport = httpx2.MockTransport(server.handle) if asynchronous: async with AsyncOpenAI(api_key="synthetic", http_client=httpx2.AsyncClient(transport=transport)) as client: - async with client.beta.agents.sessions.stream("session_test", **options) as stream: # type: ignore + async with client.beta.agents.sessions.stream("session_test", **options) as stream: # ty: ignore[invalid-argument-type] await stream.until_done() else: with OpenAI(api_key="synthetic", http_client=httpx2.Client(transport=transport)) as client: - with client.beta.agents.sessions.stream("session_test", **options) as stream: # type: ignore + with client.beta.agents.sessions.stream("session_test", **options) as stream: # ty: ignore[invalid-argument-type] stream.until_done() assert catalog.reservations == ([] if invalid else [("test-sku", 3)]) results = server.inputs()[1:] @@ -280,7 +282,7 @@ class InheritedCatalog(Catalog): pass class ShadowedCatalog(Catalog): - class Product(BaseModel): # pyright: ignore[reportIncompatibleVariableOverride] + class Product(BaseModel): # ty: ignore[invalid-attribute-override] sku: int for callback in ( @@ -587,11 +589,11 @@ def lookup(self, product: Product) -> str: return product.name class Child(Catalog): - class Product(BaseModel): # pyright: ignore[reportIncompatibleVariableOverride] + class Product(BaseModel): # ty: ignore[invalid-attribute-override] sku: int @wraps(Catalog.lookup) - def lookup(self, product: Any) -> str: # pyright: ignore[reportIncompatibleMethodOverride] + def lookup(self, product: Any) -> str: return super().lookup(product) assert function_tool(Child().lookup)({"product": {"name": "notebook"}}) == "notebook" @@ -609,7 +611,7 @@ def lookup(self, product: Product) -> str: reserve = lookup class Child(Catalog): - class Product(BaseModel): # pyright: ignore[reportIncompatibleVariableOverride] + class Product(BaseModel): # ty: ignore[invalid-attribute-override] sku: int alias = Catalog.lookup @@ -702,7 +704,9 @@ async def lookup(query: str) -> dict[str, str]: output = lookup({"query": "test"}) assert asyncio.iscoroutine(output) - assert json.loads(asyncio.run(output)) == {"query": "test"} + result = asyncio.run(output) + assert isinstance(result, str) + assert json.loads(result) == {"query": "test"} @pytest.mark.parametrize("binding", ["constructor", "pydantic", "decorator"]) diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index e2447310f8..582186ba8c 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -255,7 +255,7 @@ class ColorDetection(BaseModel): hex_color_code: str = Field(description="The hex color code of the detected color") if PYDANTIC_V1: - ColorDetection.update_forward_refs(**locals()) # type: ignore + ColorDetection.update_forward_refs(**locals()) completion = make_snapshot_request( lambda c: c.chat.completions.parse( diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index cb6a959d1c..4914241b0b 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -11,8 +11,8 @@ from inline_snapshot import ( external, snapshot, - outsource, # pyright: ignore[reportUnknownVariableType] - get_snapshot_value, # pyright: ignore[reportUnknownVariableType] + outsource, + get_snapshot_value, ) import openai @@ -37,9 +37,9 @@ _T = TypeVar("_T") # all the snapshots in this file are auto-generated from the live API -# + # you can update them with -# + # `OPENAI_LIVE=1 pytest --inline-snapshot=fix -p no:xdist -o addopts=""` diff --git a/tests/lib/live/test_websocket_roles.py b/tests/lib/live/test_websocket_roles.py index f68195d4b6..6d62eacc69 100644 --- a/tests/lib/live/test_websocket_roles.py +++ b/tests/lib/live/test_websocket_roles.py @@ -154,15 +154,15 @@ def script(socket: ServerConnection) -> None: original_async = AsyncClientConnection.send def send_then_interrupt(self: ClientConnection, message: object, *args: object, **kwargs: object) -> None: - original(self, message, *args, **kwargs) # type: ignore[arg-type] - if json.loads(message)["event_id"] == "attempted": # type: ignore[arg-type] + original(self, message, *args, **kwargs) # ty: ignore[invalid-argument-type] + if json.loads(message)["event_id"] == "attempted": # ty: ignore[invalid-argument-type] raise OSError("synthetic interruption after send") async def async_send_then_interrupt( self: AsyncClientConnection, message: object, *args: object, **kwargs: object ) -> None: - await original_async(self, message, *args, **kwargs) # type: ignore[arg-type] - if json.loads(message)["event_id"] == "attempted": # type: ignore[arg-type] + await original_async(self, message, *args, **kwargs) # ty: ignore[invalid-argument-type] + if json.loads(message)["event_id"] == "attempted": # ty: ignore[invalid-argument-type] raise OSError("synthetic interruption after send") if mode == "sync": diff --git a/tests/lib/responses/test_compaction_progress.py b/tests/lib/responses/test_compaction_progress.py index 742fe95d2f..898389b43d 100644 --- a/tests/lib/responses/test_compaction_progress.py +++ b/tests/lib/responses/test_compaction_progress.py @@ -25,7 +25,7 @@ async def test_compaction_stream_preserves_progress_and_final_output(sync: bool, {"type": "response.created", "response": {"id": "resp_test", "output": []}}, {"type": "response.output_item.added", "output_index": 0, "item": item}, *[ - {"type": "response.compaction.compacting", "item_id": "cmp_test", "output_index": 0} + dict[str, object]({"type": "response.compaction.compacting", "item_id": "cmp_test", "output_index": 0}) for _ in range(progress_count) ], {"type": "response.output_item.done", "output_index": 0, "item": final_item}, diff --git a/tests/lib/responses/test_error_diagnostics.py b/tests/lib/responses/test_error_diagnostics.py index 3ceb56fdcd..24cd7d04c1 100644 --- a/tests/lib/responses/test_error_diagnostics.py +++ b/tests/lib/responses/test_error_diagnostics.py @@ -34,7 +34,7 @@ def respond(request: httpx2.Request) -> httpx2.Response: if video: # Exercise the retained deprecated API and verify its runtime warning. with pytest.warns(DeprecationWarning, match="Sora API"): - result = client.videos.retrieve(identifier) # pyright: ignore[reportDeprecated] + result = client.videos.retrieve(identifier) else: result = (client.beta.responses if route == "beta" else client.responses).retrieve(identifier) else: @@ -46,7 +46,7 @@ def respond(request: httpx2.Request) -> httpx2.Response: if video: # Exercise the retained deprecated API and verify its runtime warning. with pytest.warns(DeprecationWarning, match="Sora API"): - result = await client_async.videos.retrieve(identifier) # pyright: ignore[reportDeprecated] + result = await client_async.videos.retrieve(identifier) else: result = await (client_async.beta.responses if route == "beta" else client_async.responses).retrieve( identifier diff --git a/tests/lib/responses/test_lifecycle_replacements.py b/tests/lib/responses/test_lifecycle_replacements.py index ff1b7fb1d0..b21321e547 100644 --- a/tests/lib/responses/test_lifecycle_replacements.py +++ b/tests/lib/responses/test_lifecycle_replacements.py @@ -164,7 +164,11 @@ async def test_completed_identity_belongs_to_one_sparse_position(sync: bool, pos {"type": "response.created", "response": {"id": "resp_fixture", "output": []}}, {"type": "response.output_item.done", "output_index": 7, "item": tool}, *( - [{"type": "response.output_item.done", "output_index": 7, "item": {**tool, "call_id": "call_other"}}] + [ + dict[str, object]( + {"type": "response.output_item.done", "output_index": 7, "item": {**tool, "call_id": "call_other"}} + ) + ] if position == "reuse-previous" else [] ), diff --git a/tests/lib/responses/test_null_output_items.py b/tests/lib/responses/test_null_output_items.py index dd9b1038d5..1788cbaf87 100644 --- a/tests/lib/responses/test_null_output_items.py +++ b/tests/lib/responses/test_null_output_items.py @@ -601,12 +601,12 @@ async def test_omitted_sparse_output_can_continue_directly(sync: bool, with_delt {"type": "response.in_progress", "response": {"id": "resp_test", "output": []}}, *( [ - { - "type": "response.function_call_arguments.delta", - "output_index": 99, - "item_id": "fc_test", - "delta": "{}", - } + dict[str, object]( + type="response.function_call_arguments.delta", + output_index=99, + item_id="fc_test", + delta="{}", + ) ] if with_delta else [] diff --git a/tests/lib/responses/test_websocket_accumulator.py b/tests/lib/responses/test_websocket_accumulator.py index 767c4a74e8..62de71c1d0 100644 --- a/tests/lib/responses/test_websocket_accumulator.py +++ b/tests/lib/responses/test_websocket_accumulator.py @@ -287,7 +287,7 @@ def script(socket: ServerConnection) -> None: else: event = {"type": "response.completed"} if ending == "null": - event["response"] = None # type: ignore[assignment] + event["response"] = None socket.send(json.dumps(event)) with script_server(script) as url: diff --git a/tests/lib/snapshots.py b/tests/lib/snapshots.py index 92b05864e4..f8501609f2 100644 --- a/tests/lib/snapshots.py +++ b/tests/lib/snapshots.py @@ -6,7 +6,7 @@ from typing_extensions import TypeVar import httpx2 -from inline_snapshot import get_snapshot_value # pyright: ignore[reportUnknownVariableType] +from inline_snapshot import get_snapshot_value from openai import OpenAI, AsyncOpenAI from tests.respx2 import MockRouter diff --git a/tests/lib/streaming/agents/test_creation_tools.py b/tests/lib/streaming/agents/test_creation_tools.py index 41aac3ac5a..199e213377 100644 --- a/tests/lib/streaming/agents/test_creation_tools.py +++ b/tests/lib/streaming/agents/test_creation_tools.py @@ -10,6 +10,7 @@ from openai import OpenAI, AsyncOpenAI, BadRequestError from openai.lib.beta.agents import function_tool +from openai.lib.beta.agents._stream import AgentSessionEventStream, AsyncAgentSessionEventStream from tests.lib.streaming.agents.test_results import ResultServer, message from tests.lib.streaming.agents.test_streams import EventBody, sdk as sdk, call, idle, session, turn_event @@ -187,6 +188,7 @@ def handler(_arguments: object) -> str: tool_handlers={"search": handler}, ) as response: stream = await response.parse() + assert isinstance(stream, AsyncAgentSessionEventStream) await stream.get_final_result() else: with sdk.beta.agents.sessions.with_streaming_response.create( @@ -197,6 +199,7 @@ def handler(_arguments: object) -> str: tool_handlers={"search": handler}, ) as response: stream = response.parse() + assert isinstance(stream, AgentSessionEventStream) stream.get_final_result() assert len(server.requests) == 2 assert "x-stainless-raw-response" not in server.requests[1].headers diff --git a/tests/lib/streaming/agents/test_output.py b/tests/lib/streaming/agents/test_output.py index ffa5c61f81..5597fd2bb5 100644 --- a/tests/lib/streaming/agents/test_output.py +++ b/tests/lib/streaming/agents/test_output.py @@ -322,7 +322,8 @@ async def test_followup_output_type_only_selects_local_parser(sdk: OpenAI | Asyn def test_enum_literals_match_responses(value: Any) -> None: from enum import Enum - enum = Enum("Example", {"A": value, "B": "other"}) + # The runtime-generated enum name is part of this schema fixture. + enum = Enum("Example", {"A": value, "B": "other"}) # ty: ignore[mismatched-type-name] model = type("EnumReport", (BaseModel,), {"__annotations__": {"value": enum}}) _assert_matches_responses(model) @@ -352,7 +353,8 @@ def test_bare_mapping_and_empty_fixed_object_match_responses() -> None: @pytest.mark.parametrize("value", ['say "hello"', "two\nlines"]) def test_single_literals_match_responses(value: Any) -> None: - model = type("LiteralReport", (BaseModel,), {"__annotations__": {"value": Literal[value]}}) + # Runtime schema construction deliberately supplies a computed Literal. + model = type("LiteralReport", (BaseModel,), {"__annotations__": {"value": Literal[value]}}) # ty: ignore[invalid-type-form] _assert_matches_responses(model) diff --git a/tests/lib/streaming/agents/test_streams.py b/tests/lib/streaming/agents/test_streams.py index b1495bfc65..855234c58f 100644 --- a/tests/lib/streaming/agents/test_streams.py +++ b/tests/lib/streaming/agents/test_streams.py @@ -754,7 +754,7 @@ async def observer(error: AgentToolError) -> None: "session_test", input="Search", tool_handlers={"search": str}, - on_tool_error=observer, # type: ignore[arg-type] + on_tool_error=observer, # ty: ignore[invalid-argument-type] ) as stream: stream.until_done() assert server.inputs()[1]["error"] == "Tool handler failed." diff --git a/tests/lib/test_assistant_tool_call_deltas.py b/tests/lib/test_assistant_tool_call_deltas.py index 647bfd381b..e6eb662ad0 100644 --- a/tests/lib/test_assistant_tool_call_deltas.py +++ b/tests/lib/test_assistant_tool_call_deltas.py @@ -82,7 +82,7 @@ def assert_tool_arguments(steps: list[RunStep]) -> None: @pytest.mark.usefixtures("assistant_tool_stream") @pytest.mark.filterwarnings("ignore:The Assistants API is deprecated:DeprecationWarning") def test_assistant_tool_call_deltas(client: OpenAI) -> None: - with client.beta.threads.runs.stream(thread_id="thread_test", assistant_id="asst_test") as stream: # pyright: ignore[reportDeprecated] + with client.beta.threads.runs.stream(thread_id="thread_test", assistant_id="asst_test") as stream: assert_tool_arguments(stream.get_final_run_steps()) @@ -90,5 +90,5 @@ def test_assistant_tool_call_deltas(client: OpenAI) -> None: @pytest.mark.usefixtures("assistant_tool_stream") @pytest.mark.filterwarnings("ignore:The Assistants API is deprecated:DeprecationWarning") async def test_async_assistant_tool_call_deltas(async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.runs.stream(thread_id="thread_test", assistant_id="asst_test") as stream: # pyright: ignore[reportDeprecated] + async with async_client.beta.threads.runs.stream(thread_id="thread_test", assistant_id="asst_test") as stream: assert_tool_arguments(await stream.get_final_run_steps()) diff --git a/tests/lib/test_assistants.py b/tests/lib/test_assistants.py index 952e1ddb45..7b80e28581 100644 --- a/tests/lib/test_assistants.py +++ b/tests/lib/test_assistants.py @@ -14,7 +14,7 @@ def test_create_and_run_helper_definition_in_sync( checking_client: OpenAI | AsyncOpenAI = client if sync else async_client assert_signatures_in_sync( - checking_client.beta.threads.create_and_run, # pyright: ignore[reportDeprecated] + checking_client.beta.threads.create_and_run, getattr(checking_client.beta.threads, method), exclude_params={"stream"}, ) @@ -25,8 +25,8 @@ def test_run_stream_method_definition_in_sync(sync: bool, client: OpenAI, async_ checking_client: OpenAI | AsyncOpenAI = client if sync else async_client assert_signatures_in_sync( - checking_client.beta.threads.runs.create, # pyright: ignore[reportDeprecated] - checking_client.beta.threads.runs.stream, # pyright: ignore[reportDeprecated] + checking_client.beta.threads.runs.create, + checking_client.beta.threads.runs.stream, exclude_params={"stream"}, ) @@ -36,7 +36,7 @@ def test_create_and_poll_method_definition_in_sync(sync: bool, client: OpenAI, a checking_client: OpenAI | AsyncOpenAI = client if sync else async_client assert_signatures_in_sync( - checking_client.beta.threads.runs.create, # pyright: ignore[reportDeprecated] - checking_client.beta.threads.runs.create_and_poll, # pyright: ignore[reportDeprecated] + checking_client.beta.threads.runs.create, + checking_client.beta.threads.runs.create_and_poll, exclude_params={"stream"}, ) diff --git a/tests/lib/test_azure.py b/tests/lib/test_azure.py index fd5067f55c..fbb7cd7f21 100644 --- a/tests/lib/test_azure.py +++ b/tests/lib/test_azure.py @@ -515,7 +515,7 @@ async def test_azure_bearer_token_redacted_async( ), # AzureOpenAI: base_url and azure_deployment specified; ignored b/c not supported ( - AzureOpenAI( # type: ignore + AzureOpenAI( # ty: ignore[no-matching-overload] api_version="2024-02-01", api_key="example API key", base_url="https://example.azure-api.net/PTU/", @@ -578,7 +578,7 @@ async def test_azure_bearer_token_redacted_async( ), # AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported ( - AsyncAzureOpenAI( # type: ignore + AsyncAzureOpenAI( # ty: ignore[no-matching-overload] api_version="2024-02-01", api_key="example API key", base_url="https://example.azure-api.net/PTU/", @@ -686,7 +686,7 @@ def test_prepare_url_deployment_endpoint( ), # AzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported ( - AzureOpenAI( # type: ignore + AzureOpenAI( # ty: ignore[no-matching-overload] api_version="2024-02-01", api_key="example API key", base_url="https://example.azure-api.net/PTU/", @@ -774,7 +774,7 @@ def test_prepare_url_deployment_endpoint( ), # AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported ( - AsyncAzureOpenAI( # type: ignore + AsyncAzureOpenAI( # ty: ignore[no-matching-overload] api_version="2024-02-01", api_key="example API key", base_url="https://example.azure-api.net/PTU/", @@ -853,7 +853,7 @@ def test_prepare_url_nondeployment_endpoint( ), # AzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported ( - AzureOpenAI( # type: ignore + AzureOpenAI( # ty: ignore[no-matching-overload] api_version="2024-02-01", api_key="example API key", base_url="https://example.azure-api.net/PTU/", @@ -934,7 +934,7 @@ def test_prepare_url_realtime(client: AzureOpenAI, base_url: str, json_data: dic ), # AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported ( - AsyncAzureOpenAI( # type: ignore + AsyncAzureOpenAI( # ty: ignore[no-matching-overload] api_version="2024-02-01", api_key="example API key", base_url="https://example.azure-api.net/PTU/", diff --git a/tests/lib/test_bedrock.py b/tests/lib/test_bedrock.py index 903d53d63a..8ba681c7ff 100644 --- a/tests/lib/test_bedrock.py +++ b/tests/lib/test_bedrock.py @@ -14,6 +14,7 @@ from tests.respx2 import MockRouter from openai._types import Omit from openai.lib.bedrock import BedrockOpenAI, AsyncBedrockOpenAI +from openai.types.responses import Response Client = Union[BedrockOpenAI, AsyncBedrockOpenAI] @@ -317,7 +318,7 @@ def test_requires_refreshable_tokens_to_use_provider_option(client_cls: type[Cli with pytest.raises(OpenAIError, match="bedrock_token_provider"): client_cls( base_url="https://example.com/openai/v1", - api_key=lambda: "provider token", # type: ignore[arg-type] + api_key=lambda: "provider token", # ty: ignore[invalid-argument-type] ) @@ -555,7 +556,7 @@ def handler(request: httpx2.Request) -> httpx2.Response: api_key="bearer token", http_client=httpx2.Client(transport=httpx2.MockTransport(handler), trust_env=False), ) - client.api_key = None # type: ignore[assignment] + client.api_key = None # ty: ignore[invalid-assignment] with pytest.raises(OpenAIError, match="bearer credential must not be empty"): client.get("/models", cast_to=httpx2.Response) @@ -1129,7 +1130,7 @@ def test_passes_responses_features_through(respx2_mock: MockRouter) -> None: response = client.responses.create( model="gpt-4o", input="hello", - tools=[{"type": "web_search_preview"}], # type: ignore[list-item] + tools=[{"type": "web_search_preview"}], ) assert response.id == "resp_123" @@ -1241,10 +1242,14 @@ def test_allows_sse_and_response_wrappers(respx2_mock: MockRouter) -> None: assert [event.type for event in events] == ["response.created"] raw_response = client.responses.with_raw_response.create(model="gpt-4o", input="hello") - assert raw_response.parse().id == "resp_123" + parsed = raw_response.parse() + assert isinstance(parsed, Response) + assert parsed.id == "resp_123" with client.responses.with_streaming_response.create(model="gpt-4o", input="hello") as response: - assert response.parse().id == "resp_123" + parsed = response.parse() + assert isinstance(parsed, Response) + assert parsed.id == "resp_123" def test_does_not_guard_responses_connect() -> None: diff --git a/tests/lib/test_bedrock_provider.py b/tests/lib/test_bedrock_provider.py index 7fd1ab971a..76a90853db 100644 --- a/tests/lib/test_bedrock_provider.py +++ b/tests/lib/test_bedrock_provider.py @@ -87,7 +87,7 @@ def test_provider_rejects_top_level_authentication_and_routing(option: str, valu OpenAIError, match=rf"`provider` cannot be combined with top-level `{option}`.*`bedrock\(\.\.\.\)`", ): - OpenAI(provider=bedrock(region="us-east-1", api_key="bedrock token"), **{option: value}) # type: ignore[arg-type] + OpenAI(provider=bedrock(region="us-east-1", api_key="bedrock token"), **{option: value}) # ty: ignore[invalid-argument-type] def test_provider_survives_with_options_and_can_be_replaced() -> None: diff --git a/tests/lib/test_bedrock_runtime.py b/tests/lib/test_bedrock_runtime.py index f0dcef2678..f4e437efe6 100644 --- a/tests/lib/test_bedrock_runtime.py +++ b/tests/lib/test_bedrock_runtime.py @@ -485,7 +485,7 @@ def __str__(self) -> str: legacy_httpx = SimpleNamespace(URL=LegacyURL) monkeypatch.setitem(sys.modules, "httpx", legacy_httpx) - client = client_cls(base_url=LegacyURL(), api_key="bedrock-token") # type: ignore[arg-type] + client = client_cls(base_url=LegacyURL(), api_key="bedrock-token") # ty: ignore[invalid-argument-type] assert client.base_url == httpx2.URL(f"{base_url}/") diff --git a/tests/lib/test_browser.py b/tests/lib/test_browser.py index d4e7fef5ab..9d65137557 100644 --- a/tests/lib/test_browser.py +++ b/tests/lib/test_browser.py @@ -1291,7 +1291,8 @@ async def test_form_read_state_is_detached_and_original_roles_still_ignore_priva legacy: dict[str, Any] = {"ref": role, "role": role, "label": role, "options": [{"label": "Old", "value": "v"}]} expected["elements"].append(deepcopy(legacy)) legacy["checked"] = object() - legacy["options"][0]["selected"] = object() + # Deliberately corrupt a nested legacy payload to test rejection. + legacy["options"][0]["selected"] = object() # ty: ignore[invalid-assignment] report["elements"].append(legacy) driver = RichReads(report) @@ -1415,7 +1416,8 @@ def find(self, _args: object) -> object: class AsyncIssuing(AsyncRichReads): @override - async def find(self, args: object) -> object: + # This test driver deliberately returns unvalidated observations. + async def find(self, args: object) -> object: # ty: ignore[invalid-method-override] return self.driver.find(args) driver = Issuing(report) diff --git a/tests/lib/test_browser_registration.py b/tests/lib/test_browser_registration.py index b28cb4ab4f..2c990d8068 100644 --- a/tests/lib/test_browser_registration.py +++ b/tests/lib/test_browser_registration.py @@ -171,14 +171,14 @@ def obscure(action: object) -> object: }, ) ) - payload = json.loads(result["output"][0]["text"]) # type: ignore[index] + payload = json.loads(result["output"][0]["text"]) # ty: ignore[invalid-argument-type, invalid-key] assert payload["error"] == "Browser action failed." gc.collect() assert not [warning for warning in recwarn if "never awaited" in str(warning.message)] async def test_async_helper_accepts_unannotated_awaitable_wrapper() -> None: - def wrapped(action: object): # type: ignore[no-untyped-def] + def wrapped(action: object): return async_read(action) browser = AsyncBrowserToolset(cast(AsyncBrowserDriver, SimpleNamespace(state=async_state, get_page_text=wrapped))) @@ -206,4 +206,4 @@ def state(self) -> BrowserState: return {"tabs": []} with pytest.raises(TypeError, match="abstract"): - MissingRead() # type: ignore[abstract] + MissingRead() # ty: ignore[call-non-callable] diff --git a/tests/lib/test_computer.py b/tests/lib/test_computer.py index 22940aec8f..8f6d8ef2b2 100644 --- a/tests/lib/test_computer.py +++ b/tests/lib/test_computer.py @@ -181,7 +181,8 @@ def __init__(self) -> None: else: assert pending.actions is not None action = pending.actions[0] - action.path = [ListPoint()] + # Deliberately inject an invalid path to exercise validation. + action.path = [ListPoint()] # ty: ignore[invalid-assignment] if mode == "sync": with pytest.raises(ComputerUseError, match="Invalid computer action"): ComputerToolset(driver).execute(pending) @@ -1481,7 +1482,7 @@ async def test_approval_callback_cannot_change_dispatched_action(mode: str) -> N requests: list[dict[str, Any]] = [] def approve(action: ComputerActionInput) -> bool: - action.type = "__getattribute__" # type: ignore[assignment] + action.type = "__getattribute__" # ty: ignore[invalid-assignment] return True await run(mode, driver, [response([call()]), FINAL], requests, before_action=approve) diff --git a/tests/lib/test_decisions_tool_runner.py b/tests/lib/test_decisions_tool_runner.py index f3f30c1af8..4c65091ae4 100644 --- a/tests/lib/test_decisions_tool_runner.py +++ b/tests/lib/test_decisions_tool_runner.py @@ -300,7 +300,8 @@ async def test_candidate_mapping_cannot_fabricate_missing_fields(lane: str) -> N class MissingID(dict[str, object]): @override - def get(self, key: str, default: object = None) -> Any: + # This adversarial mapping tests that validation does not trust get(). + def get(self, key: str, default: object = None) -> Any: # ty: ignore[invalid-method-override] reads.append(key) if key == "id": return "invented" @@ -875,7 +876,7 @@ def observe() -> str: [], observe=observe, candidates=lambda _: [DONE], - params=cast(DecisionsRunnerParams, {**PARAMS, **bad}), + params={**PARAMS, **bad}, ) @@ -923,13 +924,11 @@ async def test_final_request_can_verify_done_with_255_candidates(lane: str) -> N effects: list[str] = [] def candidates(_obs: DecisionObservation) -> list[DecisionCandidate]: - return [ - *[ - {"id": str(index), "description": "perform", "execute": lambda: effects.append("effect")} - for index in range(254) - ], - DONE, + actions: list[DecisionCandidate] = [ + {"id": str(index), "description": "perform", "execute": lambda: effects.append("effect")} + for index in range(254) ] + return [*actions, DONE] result = await run( lane, diff --git a/tests/lib/test_old_api.py b/tests/lib/test_old_api.py index bdb2a5398d..52946de503 100644 --- a/tests/lib/test_old_api.py +++ b/tests/lib/test_old_api.py @@ -11,7 +11,7 @@ def test_basic_attribute_access_works() -> None: def test_helpful_error_is_raised() -> None: with pytest.raises(APIRemovedInV1): - openai.Completion.create() # type: ignore + openai.Completion.create() # ty: ignore[unresolved-attribute] with pytest.raises(APIRemovedInV1): - openai.ChatCompletion.create() # type: ignore + openai.ChatCompletion.create() # ty: ignore[unresolved-attribute] diff --git a/tests/lib/test_realtime_websocket_contract.py b/tests/lib/test_realtime_websocket_contract.py index 63aaaf2599..4eff015562 100644 --- a/tests/lib/test_realtime_websocket_contract.py +++ b/tests/lib/test_realtime_websocket_contract.py @@ -252,15 +252,15 @@ def script(socket: ServerConnection) -> None: original_async = AsyncClientConnection.send def send_then_interrupt(self: ClientConnection, message: object, *args: object, **kwargs: object) -> None: - original(self, message, *args, **kwargs) # type: ignore[arg-type] - if json.loads(message)["event_id"] == "attempted": # type: ignore[arg-type] + original(self, message, *args, **kwargs) # ty: ignore[invalid-argument-type] + if json.loads(message)["event_id"] == "attempted": # ty: ignore[invalid-argument-type] raise OSError("synthetic interruption after send") async def async_send_then_interrupt( self: AsyncClientConnection, message: object, *args: object, **kwargs: object ) -> None: - await original_async(self, message, *args, **kwargs) # type: ignore[arg-type] - if json.loads(message)["event_id"] == "attempted": # type: ignore[arg-type] + await original_async(self, message, *args, **kwargs) # ty: ignore[invalid-argument-type] + if json.loads(message)["event_id"] == "attempted": # ty: ignore[invalid-argument-type] raise OSError("synthetic interruption after send") if mode == "sync": diff --git a/tests/lib/test_responses_tool_runner.py b/tests/lib/test_responses_tool_runner.py index a995e5bb55..336d2b66e4 100644 --- a/tests/lib/test_responses_tool_runner.py +++ b/tests/lib/test_responses_tool_runner.py @@ -483,7 +483,7 @@ async def test_function_allowed_callers_reject_before_local_execution( stream=stream, eager=eager, effects=effects, - function_tool=cast(FunctionToolParam, {**TOOL, **declaration}), + function_tool={**TOOL, **declaration}, ) assert effects == [] and len(requests) == 1 assert error.value.attempted_call_ids == error.value.completed_call_ids == () @@ -516,7 +516,7 @@ async def test_function_allowed_callers_keep_native_selected_calls( stream=stream, eager=eager, effects=effects, - function_tool=cast(FunctionToolParam, {**TOOL, **declaration}), + function_tool={**TOOL, **declaration}, ) assert result.id == "resp_final" and effects == ["recorded"] and len(requests) == 2 assert selected in requests[1]["input"] @@ -3781,7 +3781,7 @@ def to_json(self) -> str: [FINAL], requests, save=records.append, - params=cast(ResponseCreateParamsNonStreaming, {**PARAMS, **fields}), + params={**PARAMS, **fields}, ) assert records == requests == hooks == [] @@ -4633,8 +4633,9 @@ async def record(args: dict[str, object]) -> str: } call = fn("browser_click", "held", target="button", tab_id=None) if kind == "browser" else native first = resp([call, fn("record", "last", text="never")], "r") + policy: EarlyExecution if side == "suffix": - policy: EarlyExecution = {} + policy = {} else: policy = {"functions": ["browser_click"]} if kind == "browser" else {"computer": True} diff --git a/tests/lib/test_runner_server_tools.py b/tests/lib/test_runner_server_tools.py index 42a8ab3d98..862524d839 100644 --- a/tests/lib/test_runner_server_tools.py +++ b/tests/lib/test_runner_server_tools.py @@ -489,13 +489,10 @@ async def test_mcp_approval_tool_choice_on_resume(lane: str, consumed: bool, res "arguments": "{}", } remote = {**approval, "type": "mcp_call", "id": "remote", "approval_request_id": "approval", "status": "completed"} - params: ResponseCreateParamsNonStreaming = cast( - ResponseCreateParamsNonStreaming, - { - **PARAMS, - "tools": [{"type": "mcp", "server_label": "desk", "server_url": "https://fixture.invalid/mcp"}], - }, - ) + params: ResponseCreateParamsNonStreaming = { + **PARAMS, + "tools": [{"type": "mcp", "server_label": "desk", "server_url": "https://fixture.invalid/mcp"}], + } replies = [resp([approval, fn("record", "first", text="once")], "first")] if consumed: replies.append(resp([remote, fn("record", "second", text="twice")], "second")) diff --git a/tests/lib/test_vertex_provider.py b/tests/lib/test_vertex_provider.py index e522590442..cf9e4b1484 100644 --- a/tests/lib/test_vertex_provider.py +++ b/tests/lib/test_vertex_provider.py @@ -603,5 +603,6 @@ def block_auth(_request: object, _method: str, _url: str, headers: dict[str, str client.responses.create(model="fixture", input="hi") finally: release.set() - assert first.result(timeout=2).id == "resp_test" + # Executor submission loses the non-streaming overload in ty. + assert first.result(timeout=2).id == "resp_test" # ty: ignore[unresolved-attribute] assert credentials.before_request.call_count == 1 diff --git a/tests/lib/test_video_polling.py b/tests/lib/test_video_polling.py index 10076d77fc..d256324b51 100644 --- a/tests/lib/test_video_polling.py +++ b/tests/lib/test_video_polling.py @@ -15,9 +15,6 @@ from openai._types import Omit, omit from openai.types.video import Video -# The existing video helpers are deprecated, but their compatibility still matters. -# pyright: reportDeprecated=false - VIDEO_ID = "video_synthetic" diff --git a/tests/test_client.py b/tests/test_client.py index 4ee26c3f6b..b97d53574f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -18,6 +18,7 @@ import anyio import httpx2 import pytest +import httpcore2 from pydantic import ValidationError from openai import OpenAI, AsyncOpenAI, OpenAIError, APIResponseValidationError @@ -152,6 +153,7 @@ def tell(self) -> int: def _get_open_connections(client: OpenAI | AsyncOpenAI) -> int: transport = client._client._transport if isinstance(transport, httpx2.HTTPTransport) or isinstance(transport, httpx2.AsyncHTTPTransport): + assert isinstance(transport._pool, (httpcore2.ConnectionPool, httpcore2.AsyncConnectionPool)) return len(transport._pool._requests) assert type(transport).__module__ == "httpx2" @@ -359,8 +361,7 @@ def test_copy_default_query(self) -> None: def test_copy_signature(self, client: OpenAI) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( - # mypy doesn't like that we access the `__init__` property. - client.__init__, # type: ignore[misc] + client.__init__, ) copy_signature = inspect.signature(client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} @@ -411,7 +412,6 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic frame.filename.endswith(fragment) for fragment in [ # to_raw_response_wrapper leaks through the @functools.wraps() decorator. - # # removing the decorator fixes the leak for reasons we don't understand. "openai/_legacy_response.py", "openai/_response.py", @@ -437,11 +437,11 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic def test_request_timeout(self, client: OpenAI) -> None: request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == DEFAULT_TIMEOUT request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx2.Timeout(100.0))) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == httpx2.Timeout(100.0) def test_client_timeout_option(self) -> None: @@ -454,7 +454,7 @@ def test_client_timeout_option(self) -> None: ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == httpx2.Timeout(0) client.close() @@ -471,7 +471,7 @@ def test_http_client_timeout_option(self) -> None: ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == httpx2.Timeout(None) client.close() @@ -487,7 +487,7 @@ def test_http_client_timeout_option(self) -> None: ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == DEFAULT_TIMEOUT client.close() @@ -503,7 +503,7 @@ def test_http_client_timeout_option(self) -> None: ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == DEFAULT_TIMEOUT # our default client.close() @@ -688,7 +688,7 @@ def test_workload_identity_is_mutually_exclusive_with_api_key(self) -> None: OpenAI( base_url=base_url, api_key=api_key, - workload_identity=workload_identity, # type: ignore[reportArgumentType] + workload_identity=workload_identity, organization="org_123", _strict_response_validation=True, ) @@ -1120,8 +1120,8 @@ def test_binary_content_upload_with_body_is_deprecated(self, respx2_mock: MockRo @pytest.mark.parametrize("client", [False], indirect=True) def test_bare_container_response(self, respx2_mock: MockRouter, client: OpenAI) -> None: class Model(BaseModel): - metadata: dict # type: ignore[type-arg] - items: list # type: ignore[type-arg] + metadata: dict + items: list data = {"metadata": {"key": "value"}, "items": [1, "two"]} respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json=data)) @@ -1199,7 +1199,7 @@ def test_base_url_setter(self) -> None: ) assert client.base_url == "https://example.com/from_init/" - client.base_url = "https://example.com/from_setter" # type: ignore[assignment] + client.base_url = "https://example.com/from_setter" assert client.base_url == "https://example.com/from_setter/" @@ -1375,7 +1375,7 @@ class Model(BaseModel): ) response = non_strict_client.get("/foo", cast_to=Model) - assert isinstance(response, str) # type: ignore[unreachable] + assert isinstance(response, str) strict_client.close() non_strict_client.close() @@ -1415,7 +1415,7 @@ def test_parse_retry_after_header( headers = httpx2.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = client._calculate_retry_timeout(remaining_retries, options, headers) - assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] + assert calculated == pytest.approx(timeout, 0.5 * 0.875) @pytest.mark.parametrize( "headers,should_retry", @@ -1911,8 +1911,7 @@ async def test_copy_default_query(self) -> None: def test_copy_signature(self, async_client: AsyncOpenAI) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( - # mypy doesn't like that we access the `__init__` property. - async_client.__init__, # type: ignore[misc] + async_client.__init__, ) copy_signature = inspect.signature(async_client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} @@ -1963,7 +1962,6 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic frame.filename.endswith(fragment) for fragment in [ # to_raw_response_wrapper leaks through the @functools.wraps() decorator. - # # removing the decorator fixes the leak for reasons we don't understand. "openai/_legacy_response.py", "openai/_response.py", @@ -1989,13 +1987,13 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic async def test_request_timeout(self, async_client: AsyncOpenAI) -> None: request = async_client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == DEFAULT_TIMEOUT request = async_client._build_request( FinalRequestOptions(method="get", url="/foo", timeout=httpx2.Timeout(100.0)) ) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == httpx2.Timeout(100.0) async def test_client_timeout_option(self) -> None: @@ -2008,7 +2006,7 @@ async def test_client_timeout_option(self) -> None: ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == httpx2.Timeout(0) await client.close() @@ -2025,7 +2023,7 @@ async def test_http_client_timeout_option(self) -> None: ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == httpx2.Timeout(None) await client.close() @@ -2041,7 +2039,7 @@ async def test_http_client_timeout_option(self) -> None: ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == DEFAULT_TIMEOUT await client.close() @@ -2057,7 +2055,7 @@ async def test_http_client_timeout_option(self) -> None: ) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx2.Timeout(**request.extensions["timeout"]) # type: ignore + timeout = httpx2.Timeout(**request.extensions["timeout"]) assert timeout == DEFAULT_TIMEOUT # our default await client.close() @@ -2512,8 +2510,8 @@ async def test_binary_content_upload_with_body_is_deprecated( @pytest.mark.parametrize("async_client", [False], indirect=True) async def test_bare_container_response(self, respx2_mock: MockRouter, async_client: AsyncOpenAI) -> None: class Model(BaseModel): - metadata: dict # type: ignore[type-arg] - items: list # type: ignore[type-arg] + metadata: dict + items: list data = {"metadata": {"key": "value"}, "items": [1, "two"]} respx2_mock.get("/foo").mock(return_value=httpx2.Response(200, json=data)) @@ -2593,7 +2591,7 @@ async def test_base_url_setter(self) -> None: ) assert client.base_url == "https://example.com/from_init/" - client.base_url = "https://example.com/from_setter" # type: ignore[assignment] + client.base_url = "https://example.com/from_setter" assert client.base_url == "https://example.com/from_setter/" @@ -2770,7 +2768,7 @@ class Model(BaseModel): ) response = await non_strict_client.get("/foo", cast_to=Model) - assert isinstance(response, str) # type: ignore[unreachable] + assert isinstance(response, str) await strict_client.close() await non_strict_client.close() @@ -2810,7 +2808,7 @@ async def test_parse_retry_after_header( headers = httpx2.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers) - assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] + assert calculated == pytest.approx(timeout, 0.5 * 0.875) @pytest.mark.respx2(base_url=base_url) async def test_does_not_retry_retry_after_above_max( @@ -3543,12 +3541,12 @@ async def test_invalid_request_retry_limit(is_async: bool, value: Any) -> None: error = ValueError if isinstance(value, int) else TypeError try: with pytest.raises(error, match="max_retries"): - client.with_options(max_retries=cast(Any, value)) + client.with_options(max_retries=value) with pytest.raises(error, match="max_retries"): if isinstance(client, AsyncOpenAI): - await client.get("/test", cast_to=object, options={"max_retries": cast(Any, value)}) + await client.get("/test", cast_to=object, options={"max_retries": value}) else: - client.get("/test", cast_to=object, options={"max_retries": cast(Any, value)}) + client.get("/test", cast_to=object, options={"max_retries": value}) finally: if isinstance(client, AsyncOpenAI): await client.close() diff --git a/tests/test_files.py b/tests/test_files.py index 51ca9f0acc..465ecba2bf 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -109,9 +109,10 @@ async def test_async_file_tuple_with_pathlike_content_and_headers() -> None: def test_string_not_allowed() -> None: with pytest.raises(TypeError, match="Expected file types input to be a FileContent type or to be a tuple"): - to_httpx_files( + # Deliberately invalid file input exercises runtime rejection. + to_httpx_files( # ty: ignore[no-matching-overload] { - "file": "foo", # type: ignore + "file": "foo", } ) diff --git a/tests/test_httpx2.py b/tests/test_httpx2.py index bcb1036cf7..a693dd8807 100644 --- a/tests/test_httpx2.py +++ b/tests/test_httpx2.py @@ -637,7 +637,7 @@ async def async_response(request: httpx2.Request) -> httpx2.Response: http_client=openai.DefaultHttpx2Client(transport=httpx2.MockTransport(sync_response), trust_env=False), max_retries=0, ) as sync_client: - with sync_client.beta.threads.runs.stream( # pyright: ignore[reportDeprecated] + with sync_client.beta.threads.runs.stream( assistant_id="asst_test", thread_id="thread_test", event_handler=sync_handler ) as stream: with pytest.raises(error_type, match="assistant stream failure"): @@ -653,7 +653,7 @@ async def async_response(request: httpx2.Request) -> httpx2.Response: http_client=openai.DefaultAsyncHttpx2Client(transport=httpx2.MockTransport(async_response), trust_env=False), max_retries=0, ) as async_client: - async with async_client.beta.threads.runs.stream( # pyright: ignore[reportDeprecated] + async with async_client.beta.threads.runs.stream( assistant_id="asst_test", thread_id="thread_test", event_handler=async_handler ) as async_stream: with pytest.raises(error_type, match="assistant stream failure"): @@ -745,7 +745,7 @@ async def async_response(request: httpx2.Request) -> httpx2.Response: ), max_retries=0, ) as client: - with client.beta.threads.runs.stream( # pyright: ignore[reportDeprecated] + with client.beta.threads.runs.stream( assistant_id="asst_test", thread_id="thread_test", event_handler=handler, @@ -770,7 +770,7 @@ async def async_response(request: httpx2.Request) -> httpx2.Response: ), max_retries=0, ) as client: - async with client.beta.threads.runs.stream( # pyright: ignore[reportDeprecated] + async with client.beta.threads.runs.stream( assistant_id="asst_test", thread_id="thread_test", event_handler=handler, diff --git a/tests/test_image_safety_identifier.py b/tests/test_image_safety_identifier.py index 18ec850495..27f3cb0532 100644 --- a/tests/test_image_safety_identifier.py +++ b/tests/test_image_safety_identifier.py @@ -82,8 +82,8 @@ def handler(request: httpx2.Request) -> httpx2.Response: events = [event async for event in result] if isinstance(result, AsyncStream) else list(result) assert len(events) == 1 event = events[0] - assert event.type == event_type assert isinstance(event, (ImageGenCompletedEvent, ImageEditCompletedEvent)) + assert event.type == event_type assert event.safety_identifier == expected else: assert result.safety_identifier == expected diff --git a/tests/test_lazy_imports.py b/tests/test_lazy_imports.py index 6224da164f..364a28e804 100644 --- a/tests/test_lazy_imports.py +++ b/tests/test_lazy_imports.py @@ -35,7 +35,7 @@ assert_type(openai.ComputerToolset, type[CanonicalComputerToolset]) assert_type(openai.AsyncComputerToolset, type[CanonicalAsyncComputerToolset]) assert_type(openai.ComputerDriver, type[CanonicalComputerDriver]) - assert_type(openai.AsyncComputerDriver, type[CanonicalAsyncComputerDriver]) + _: type[CanonicalAsyncComputerDriver] = openai.AsyncComputerDriver def _run_python(source: str) -> None: diff --git a/tests/test_models.py b/tests/test_models.py index 4a7892d9dc..50c1ce0210 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -349,7 +349,7 @@ class Model(BaseModel): assert m.foo.name == "3" else: assert isinstance(m.foo, Submodel1) - assert m.foo.name == 3 # type: ignore + assert m.foo.name == 3 # ty: ignore[unresolved-attribute] def test_list_of_unions() -> None: @@ -411,10 +411,10 @@ class Model(BaseModel): def test_bare_dict_annotation() -> None: # a bare `dict` has no type arguments so the values are left as-is class Model(BaseModel): - metadata: dict # type: ignore[type-arg] + metadata: dict m = Model.construct(metadata={"key": "value"}) - assert m.metadata == {"key": "value"} # pyright: ignore[reportUnknownMemberType] + assert m.metadata == {"key": "value"} assert construct_type(value={"key": "value"}, type_=dict) == {"key": "value"} assert construct_type(value={"key": "value"}, type_=Dict) == {"key": "value"} @@ -427,10 +427,10 @@ class Model(BaseModel): def test_bare_list_annotation() -> None: # a bare `list` has no type arguments so the entries are left as-is class Model(BaseModel): - items: list # type: ignore[type-arg] + items: list m = Model.construct(items=[{"key": "value"}, 1]) - assert m.items == [{"key": "value"}, 1] # pyright: ignore[reportUnknownMemberType] + assert m.items == [{"key": "value"}, 1] assert construct_type(value=[1, 2], type_=list) == [1, 2] assert construct_type(value=[1, 2], type_=List) == [1, 2] @@ -528,7 +528,7 @@ class Model(BaseModel): assert Model.construct(bar=1).bar == 1 assert Model.construct(bar=10.9).bar == 10.9 - assert Model.construct(bar="19").bar == "19" # type: ignore[comparison-overlap] + assert Model.construct(bar="19").bar == "19" assert Model.construct(bar=False).bar is False @@ -753,7 +753,7 @@ class B(BaseModel): ) assert isinstance(m, B) assert m.type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] + assert m.data == "foo" m = construct_type( value={"type": "a", "data": 100}, @@ -766,7 +766,7 @@ class B(BaseModel): # if the expected type is a str assert m.data == "100" else: - assert m.data == 100 # type: ignore[comparison-overlap] + assert m.data == 100 def test_discriminated_unions_unknown_variant() -> None: @@ -787,8 +787,8 @@ class B(BaseModel): # just chooses the first variant assert isinstance(m, A) - assert m.type == "c" # type: ignore[comparison-overlap] - assert m.data == None # type: ignore[unreachable] + assert m.type == "c" + assert m.data == None assert m.new_thing == "bar" @@ -814,7 +814,7 @@ class C(BaseModel): ) assert isinstance(m, B) assert m.type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] + assert m.data == "foo" m = construct_type( value={"type": "c", "data": "foo"}, @@ -822,7 +822,7 @@ class C(BaseModel): ) assert isinstance(m, C) assert m.type == "c" - assert m.data == "foo" # type: ignore[comparison-overlap] + assert m.data == "foo" def test_discriminated_unions_with_aliases_invalid_data() -> None: @@ -842,7 +842,7 @@ class B(BaseModel): ) assert isinstance(m, B) assert m.foo_type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] + assert m.data == "foo" m = construct_type( value={"type": "a", "data": 100}, @@ -855,7 +855,7 @@ class B(BaseModel): # if the expected type is a str assert m.data == "100" else: - assert m.data == 100 # type: ignore[comparison-overlap] + assert m.data == 100 def test_discriminated_unions_overlapping_discriminators_invalid_data() -> None: @@ -875,7 +875,7 @@ class B(BaseModel): ) assert isinstance(m, B) assert m.type == "a" - assert m.data == "foo" # type: ignore[comparison-overlap] + assert m.data == "foo" def test_discriminated_unions_invalid_data_uses_cache() -> None: @@ -898,7 +898,7 @@ class B(BaseModel): ) assert isinstance(m, B) assert m.type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] + assert m.data == "foo" discriminator = DISCRIMINATOR_CACHE.get(UnionType) assert discriminator is not None @@ -908,7 +908,7 @@ class B(BaseModel): ) assert isinstance(m, B) assert m.type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] + assert m.data == "foo" # if the discriminator details object stays the same between invocations then # we hit the cache @@ -917,7 +917,7 @@ class B(BaseModel): @pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") def test_type_alias_type() -> None: - Alias = TypeAliasType("Alias", str) # pyright: ignore + Alias = TypeAliasType("Alias", str) class Model(BaseModel): alias: Alias @@ -1024,7 +1024,7 @@ class Item(BaseModel): prop: int class Model(BaseModel): - __pydantic_extra__: Dict[str, Item] = Field(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + __pydantic_extra__: Dict[str, Item] = Field(init=False) other: str diff --git a/tests/test_module_client.py b/tests/test_module_client.py index 6b8076c6f6..950ce62421 100644 --- a/tests/test_module_client.py +++ b/tests/test_module_client.py @@ -25,7 +25,8 @@ def reset_state() -> None: openai.default_headers = None openai.default_query = None openai.http_client = None - openai.api_type = _os.environ.get("OPENAI_API_TYPE") # type: ignore + # Restore the raw environment value, matching module initialization. + openai.api_type = _os.environ.get("OPENAI_API_TYPE") # ty: ignore[invalid-assignment] openai.api_version = None openai.azure_endpoint = None openai.azure_ad_token = None diff --git a/tests/test_required_args.py b/tests/test_required_args.py index 5d1a5224ff..4eed6c4230 100644 --- a/tests/test_required_args.py +++ b/tests/test_required_args.py @@ -11,7 +11,7 @@ def foo(a: str | None = None) -> str | None: return a with pytest.raises(TypeError, match=r"foo\(\) takes 1 argument\(s\) but 2 were given"): - foo("a", "b") # type: ignore + foo("a", "b") # ty: ignore[too-many-positional-arguments] def test_positional_param() -> None: diff --git a/tests/test_transform.py b/tests/test_transform.py index 8fba1197f6..1341779e2a 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -190,26 +190,26 @@ class DateModel(BaseModel): async def test_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") tz = "+00:00" if PYDANTIC_V1 else "Z" - assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] - assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} # type: ignore[comparison-overlap] + assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} dt = dt.replace(tzinfo=None) - assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] - assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] + assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692"} + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692"} - assert await transform({"foo": None}, DateDict, use_async) == {"foo": None} # type: ignore[comparison-overlap] - assert await transform(DateModel(foo=None), Any, use_async) == {"foo": None} # type: ignore - assert await transform({"foo": date.fromisoformat("2023-02-23")}, DateDict, use_async) == {"foo": "2023-02-23"} # type: ignore[comparison-overlap] + assert await transform({"foo": None}, DateDict, use_async) == {"foo": None} + assert await transform(DateModel(foo=None), Any, use_async) == {"foo": None} + assert await transform({"foo": date.fromisoformat("2023-02-23")}, DateDict, use_async) == {"foo": "2023-02-23"} assert await transform(DateModel(foo=date.fromisoformat("2023-02-23")), DateDict, use_async) == { "foo": "2023-02-23" - } # type: ignore[comparison-overlap] + } @parametrize @pytest.mark.asyncio async def test_optional_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - assert await transform({"bar": dt}, DatetimeDict, use_async) == {"bar": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] + assert await transform({"bar": dt}, DatetimeDict, use_async) == {"bar": "2023-02-23T14:16:36.337692+00:00"} assert await transform({"bar": None}, DatetimeDict, use_async) == {"bar": None} @@ -220,7 +220,7 @@ async def test_required_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") assert await transform({"required": dt}, DatetimeDict, use_async) == { "required": "2023-02-23T14:16:36.337692+00:00" - } # type: ignore[comparison-overlap] + } assert await transform({"required": None}, DatetimeDict, use_async) == {"required": None} @@ -229,9 +229,7 @@ async def test_required_iso8601_format(use_async: bool) -> None: @pytest.mark.asyncio async def test_union_datetime(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - assert await transform({"union": dt}, DatetimeDict, use_async) == { # type: ignore[comparison-overlap] - "union": "2023-02-23T14:16:36.337692+00:00" - } + assert await transform({"union": dt}, DatetimeDict, use_async) == {"union": "2023-02-23T14:16:36.337692+00:00"} assert await transform({"union": "foo"}, DatetimeDict, use_async) == {"union": "foo"} @@ -241,7 +239,7 @@ async def test_union_datetime(use_async: bool) -> None: async def test_nested_list_iso6801_format(use_async: bool) -> None: dt1 = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") dt2 = parse_datetime("2022-01-15T06:34:23Z") - assert await transform({"list_": [dt1, dt2]}, DatetimeDict, use_async) == { # type: ignore[comparison-overlap] + assert await transform({"list_": [dt1, dt2]}, DatetimeDict, use_async) == { "list_": ["2023-02-23T14:16:36.337692+00:00", "2022-01-15T06:34:23+00:00"] } @@ -252,7 +250,7 @@ async def test_datetime_custom_format(use_async: bool) -> None: dt = parse_datetime("2022-01-15T06:34:23Z") result = await transform(dt, Annotated[datetime, PropertyInfo(format="custom", format_template="%H")], use_async) - assert result == "06" # type: ignore[comparison-overlap] + assert result == "06" class DateDictWithRequiredAlias(TypedDict, total=False): @@ -262,10 +260,10 @@ class DateDictWithRequiredAlias(TypedDict, total=False): @parametrize @pytest.mark.asyncio async def test_datetime_with_alias(use_async: bool) -> None: - assert await transform({"required_prop": None}, DateDictWithRequiredAlias, use_async) == {"prop": None} # type: ignore[comparison-overlap] + assert await transform({"required_prop": None}, DateDictWithRequiredAlias, use_async) == {"prop": None} assert await transform( {"required_prop": date.fromisoformat("2023-02-23")}, DateDictWithRequiredAlias, use_async - ) == {"prop": "2023-02-23"} # type: ignore[comparison-overlap] + ) == {"prop": "2023-02-23"} class MyModel(BaseModel): @@ -418,7 +416,7 @@ async def test_bare_dict_annotation(use_async: bool) -> None: """Bare dictionaries still serialize their values.""" class BareDict(TypedDict): - metadata: dict # type: ignore[type-arg] + metadata: dict assert await transform({"metadata": {"key": "value"}}, BareDict, use_async) == {"metadata": {"key": "value"}} assert await transform({"key": "value"}, dict, use_async) == {"key": "value"} @@ -435,7 +433,7 @@ async def test_bare_list_annotation(use_async: bool) -> None: """Bare lists still serialize their entries.""" class BareList(TypedDict): - items: list # type: ignore[type-arg] + items: list assert await transform({"items": [{"foo_baz": "bar"}]}, BareList, use_async) == {"items": [{"foo_baz": "bar"}]} assert await transform([1, 2, 3], list, use_async) == [1, 2, 3] @@ -470,15 +468,15 @@ async def test_base64_file_input(use_async: bool) -> None: # pathlib.Path is automatically converted to base64 assert await transform({"foo": SAMPLE_FILE_PATH}, TypedDictBase64Input, use_async) == { "foo": "SGVsbG8sIHdvcmxkIQo=" - } # type: ignore[comparison-overlap] + } # io instances are automatically converted to base64 assert await transform({"foo": io.StringIO("Hello, world!")}, TypedDictBase64Input, use_async) == { "foo": "SGVsbG8sIHdvcmxkIQ==" - } # type: ignore[comparison-overlap] + } assert await transform({"foo": io.BytesIO(b"Hello, world!")}, TypedDictBase64Input, use_async) == { "foo": "SGVsbG8sIHdvcmxkIQ==" - } # type: ignore[comparison-overlap] + } @parametrize @@ -516,7 +514,7 @@ class DateDictWithNotRequiredAlias(TypedDict): @parametrize @pytest.mark.asyncio async def test_not_required_transforms(use_async: bool) -> None: - assert await transform(cast(Dict[str, Any], {}), DateDictWithNotRequiredAlias, use_async) == {} + assert await transform({}, DateDictWithNotRequiredAlias, use_async) == {} assert await transform({"optional_prop": date(2023, 2, 23)}, DateDictWithNotRequiredAlias, use_async) == { "prop": "2023-02-23" } diff --git a/tests/test_union_parsing.py b/tests/test_union_parsing.py index 23c7f1d935..7585eb923d 100644 --- a/tests/test_union_parsing.py +++ b/tests/test_union_parsing.py @@ -59,6 +59,6 @@ async def test_union_response_fallback( if discriminated: assert isinstance(result, NumberVariant) assert result.kind == "number" - assert result.data == "unexpected" # type: ignore[comparison-overlap] + assert result.data == "unexpected" else: assert result == value diff --git a/tests/test_utils/test_assert_matches_type.py b/tests/test_utils/test_assert_matches_type.py new file mode 100644 index 0000000000..79561cd217 --- /dev/null +++ b/tests/test_utils/test_assert_matches_type.py @@ -0,0 +1,12 @@ +from typing import Any, Sequence + +import pytest + +from tests.utils import assert_matches_type + + +@pytest.mark.parametrize("expected", [list[int], Sequence[int]]) +def test_collection_items_are_validated(expected: Any) -> None: + assert_matches_type(expected, [1, 2], path=["items"]) + with pytest.raises(AssertionError): + assert_matches_type(expected, [1, "wrong"], path=["items"]) diff --git a/tests/test_utils/test_datetime_parse.py b/tests/test_utils/test_datetime_parse.py index 44c33a4ccb..7713dfc244 100644 --- a/tests/test_utils/test_datetime_parse.py +++ b/tests/test_utils/test_datetime_parse.py @@ -51,7 +51,7 @@ def create_tz(minutes: int) -> timezone: ], ) def test_date_parsing(value: Union[str, bytes, int, float], result: Union[date, Type[Exception]]) -> None: - if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + if type(result) == type and issubclass(result, Exception): # ty: ignore[invalid-argument-type] with pytest.raises(result): parse_date(value) else: @@ -103,7 +103,7 @@ def test_date_parsing(value: Union[str, bytes, int, float], result: Union[date, ], ) def test_datetime_parsing(value: Union[str, bytes, int, float], result: Union[datetime, Type[Exception]]) -> None: - if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + if type(result) == type and issubclass(result, Exception): # ty: ignore[invalid-argument-type] with pytest.raises(result): parse_datetime(value) else: diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py index 240c64562f..13a359162c 100644 --- a/tests/test_utils/test_json.py +++ b/tests/test_utils/test_json.py @@ -93,7 +93,7 @@ class User(pydantic.BaseModel): if _compat.PYDANTIC_V1: # to handle forward references in Pydantic v1 - User.update_forward_refs(**locals()) # type: ignore[reportDeprecated] + User.update_forward_refs(**locals()) address = Address(street="123 Main St") user = User(name="Diana", address=address) diff --git a/tests/test_utils/test_typing.py b/tests/test_utils/test_typing.py index 535935b9e1..55f50fc10b 100644 --- a/tests/test_utils/test_typing.py +++ b/tests/test_utils/test_typing.py @@ -2,6 +2,8 @@ from typing import Generic, TypeVar, cast +import pytest + from openai._utils import extract_type_var_from_base _T = TypeVar("_T") @@ -24,12 +26,22 @@ class SubclassGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T, _T2, _T3]) class SubclassDifferentOrderGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T2, _T, _T3]): ... +def test_extract_type_var_without_generic_base() -> None: + with pytest.raises(RuntimeError, match="Expected a generic subclass"): + extract_type_var_from_base( + object, + index=0, + generic_bases=(BaseGeneric,), + failure_message="Expected a generic subclass", + ) + + def test_extract_type_var() -> None: assert ( extract_type_var_from_base( BaseGeneric[int], index=0, - generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), + generic_bases=(BaseGeneric,), ) == int ) @@ -40,7 +52,7 @@ def test_extract_type_var_generic_subclass() -> None: extract_type_var_from_base( SubclassGeneric[int], index=0, - generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), + generic_bases=(BaseGeneric,), ) == int ) diff --git a/tests/test_uv_workflows.py b/tests/test_uv_workflows.py index 665c7d2191..da620fdbe7 100644 --- a/tests/test_uv_workflows.py +++ b/tests/test_uv_workflows.py @@ -4440,8 +4440,8 @@ def test_new_extras_cannot_publish_previously_locked_transitive_packages( base_edges: dict[tuple[str, str], list[dict[str, object]]] = {} head_edges: dict[tuple[str, str], list[dict[str, object]]] = {} parent_optional: dict[str, list[dict[str, object]]] = {"new-extra": [{"name": "existing-plugin"}]} - base_optional = {("parent", "1"): dict(parent_optional)} - head_optional = {("parent", "1"): dict(parent_optional)} + base_optional: dict[tuple[str, str], dict[str, list[dict[str, object]]]] = {("parent", "1"): dict(parent_optional)} + head_optional: dict[tuple[str, str], dict[str, list[dict[str, object]]]] = {("parent", "1"): dict(parent_optional)} constraints: list[str] | None = None markers: dict[tuple[str, str], list[str]] | None = None @@ -5013,9 +5013,9 @@ def test_security_updates_preserve_bounded_disjunctive_requirement_markers( def test_security_floors_can_safely_split_existing_marked_resolution_domains( tmp_path: Path, variant: str, accepted: bool ) -> None: - original = "danger>=1,<3,!=2.0.*; python_version < '3.14'" - low = "danger>=1.6,<3,!=2.0.*; python_version >= '3.10' and python_version < '3.11'" - high = "danger>=2.6,<3,!=2.0.*; python_version >= '3.11' and python_version < '3.14'" + original: str = "danger>=1,<3,!=2.0.*; python_version < '3.14'" + low: str = "danger>=1.6,<3,!=2.0.*; python_version >= '3.10' and python_version < '3.11'" + high: str = "danger>=2.6,<3,!=2.0.*; python_version >= '3.11' and python_version < '3.14'" scope = variant if variant in {"optional", "constraint", "group"} else "runtime" if variant == "implicit-lower": @@ -5039,11 +5039,13 @@ def test_security_floors_can_safely_split_existing_marked_resolution_domains( low = low.replace("danger>=", "danger[other]>=") high = high.replace("danger>=", "danger[other]>=") - replacements = [value for value in (low, high) if value] - base_requirements = [original] if scope == "runtime" else [] - head_requirements = replacements if scope == "runtime" else [] - base_optional = {"feature": [original]} if scope == "optional" or variant == "moved-group" else None - head_optional = ( + replacements: list[str] = [value for value in (low, high) if value] + base_requirements: list[str] = [original] if scope == "runtime" else [] + head_requirements: list[str] = replacements if scope == "runtime" else [] + base_optional: dict[str, list[str]] | None = ( + {"feature": [original]} if scope == "optional" or variant == "moved-group" else None + ) + head_optional: dict[str, list[str]] | None = ( {"different": replacements} if variant == "moved-group" else {"feature": replacements} @@ -5052,10 +5054,10 @@ def test_security_floors_can_safely_split_existing_marked_resolution_domains( ) if variant == "moved-group": base_requirements = head_requirements = [] - base_constraints = [original] if scope == "constraint" else None - head_constraints = replacements if scope == "constraint" else None - base_groups = {"reviewed": [original]} if scope == "group" else None - head_groups = {"reviewed": replacements} if scope == "group" else None + base_constraints: list[str] | None = [original] if scope == "constraint" else None + head_constraints: list[str] | None = replacements if scope == "constraint" else None + base_groups: dict[str, list[str]] | None = {"reviewed": [original]} if scope == "group" else None + head_groups: dict[str, list[str]] | None = {"reviewed": replacements} if scope == "group" else None low_domain = "python_full_version >= '3.10' and python_full_version < '3.11'" high_domain = "python_full_version >= '3.11'" if scope in {"constraint", "group"}: diff --git a/tests/test_websocket_connection_options.py b/tests/test_websocket_connection_options.py index 0a1f496840..e7cc2bed6d 100644 --- a/tests/test_websocket_connection_options.py +++ b/tests/test_websocket_connection_options.py @@ -1,5 +1,3 @@ -# An invalid native-sync literal becoming accepted must fail the type check. -# pyright: reportUnnecessaryTypeIgnoreComment=true from typing import TYPE_CHECKING from openai import types @@ -41,7 +39,7 @@ def native_options_contract( "max_size": None, "max_queue": (8, 2), } - invalid_sync: SyncWebSocketConnectionOptions = {"write_limit": 65536} # pyright: ignore[reportAssignmentType] + invalid_sync: SyncWebSocketConnectionOptions = {"write_limit": 65536} # ty: ignore[invalid-key] # The existing names still support async write limits on all supported # websocket versions, including through the generated public entrypoint. @@ -53,7 +51,7 @@ def native_options_contract( def beta_realtime_options_contract(client: OpenAI, async_client: AsyncOpenAI) -> None: client.beta.realtime.connect(model="test", websocket_connection_options={"max_size": 512}) - client.beta.realtime.connect(model="test", websocket_connection_options={"write_limit": 65536}) # pyright: ignore[reportArgumentType] + client.beta.realtime.connect(model="test", websocket_connection_options={"write_limit": 65536}) # ty: ignore[invalid-argument-type, invalid-key] async_client.beta.realtime.connect(model="test", websocket_connection_options={"write_limit": 65536}) def translation_options_contract( @@ -65,7 +63,7 @@ def translation_options_contract( invalid_sync = TranslationSession( client.realtime.translations, model="test", - websocket_connection_options={"write_limit": 65536}, # pyright: ignore[reportArgumentType] + websocket_connection_options={"write_limit": 65536}, # ty: ignore[invalid-argument-type, invalid-key] ) valid_async = AsyncTranslationSession( async_client.realtime.translations, model="test", websocket_connection_options={"write_limit": 65536} @@ -79,13 +77,13 @@ def synchronous_options_contract(client: OpenAI) -> None: client.live.connect(websocket_connection_options={"extensions": None, "subprotocols": None}) # Native sync clients do not implement write_limit on any supported version. - client.realtime.connect(model="test", websocket_connection_options={"write_limit": 65536}) # pyright: ignore[reportArgumentType] - client.responses.connect(websocket_connection_options={"write_limit": 65536}) # pyright: ignore[reportArgumentType] - client.beta.responses.connect(websocket_connection_options={"write_limit": 65536}) # pyright: ignore[reportArgumentType] - client.live.connect(websocket_connection_options={"write_limit": 65536}) # pyright: ignore[reportArgumentType] - client.live.sideband.connect(session_id="live_1", websocket_connection_options={"write_limit": 65536}) # pyright: ignore[reportArgumentType] - client.live.forks.connect(session_id="live_1", websocket_connection_options={"write_limit": 65536}) # pyright: ignore[reportArgumentType] - client.realtime.translations.connect("test", websocket_connection_options={"write_limit": 65536}) # pyright: ignore[reportArgumentType] + client.realtime.connect(model="test", websocket_connection_options={"write_limit": 65536}) # ty: ignore[invalid-argument-type, invalid-key] + client.responses.connect(websocket_connection_options={"write_limit": 65536}) # ty: ignore[invalid-argument-type, invalid-key] + client.beta.responses.connect(websocket_connection_options={"write_limit": 65536}) # ty: ignore[invalid-argument-type, invalid-key] + client.live.connect(websocket_connection_options={"write_limit": 65536}) # ty: ignore[invalid-argument-type, invalid-key] + client.live.sideband.connect(session_id="live_1", websocket_connection_options={"write_limit": 65536}) # ty: ignore[invalid-argument-type, invalid-key] + client.live.forks.connect(session_id="live_1", websocket_connection_options={"write_limit": 65536}) # ty: ignore[invalid-argument-type, invalid-key] + client.realtime.translations.connect("test", websocket_connection_options={"write_limit": 65536}) # ty: ignore[invalid-argument-type, invalid-key] def asynchronous_options_contract(client: AsyncOpenAI) -> None: original: types.WebSocketConnectionOptions = {"write_limit": 65536, "max_queue": 8} diff --git a/tests/test_x509_workload_identity_hardening.py b/tests/test_x509_workload_identity_hardening.py index 11eb8e04af..dc967eec5a 100644 --- a/tests/test_x509_workload_identity_hardening.py +++ b/tests/test_x509_workload_identity_hardening.py @@ -947,7 +947,8 @@ async def send(self, request: httpx2.Request, **kwargs: Any) -> httpx2.Response: both_arrived.set() await asyncio.wait_for(both_arrived.wait(), timeout=5) copied = httpx2.Request(request.method, request.url, headers=dict(request.headers)) - return await Context().run(asyncio.create_task, super().send(copied, **kwargs)) + # Context.run forwards the task result; ty loses its type variable here. + return await Context().run(asyncio.create_task, super().send(copied, **kwargs)) # ty: ignore[invalid-return-type] transport = CrossContextClient(transport=httpx2.MockTransport(handler), event_hooks={"request": [replace]}) clients = [ diff --git a/tests/utils.py b/tests/utils.py index dafbe17519..178c9c02f6 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -5,9 +5,9 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Sequence, Generator, ForwardRef, cast +from typing import Any, TypeVar, Sequence, Generator, ForwardRef from datetime import date, datetime -from typing_extensions import Literal, get_args, get_origin, assert_type +from typing_extensions import Literal, get_args, get_origin import rich @@ -29,7 +29,7 @@ def evaluate_forwardref(forwardref: ForwardRef, globalns: dict[str, Any]) -> type: - return eval(str(forwardref), globalns) # type: ignore[no-any-return] + return eval(str(forwardref), globalns) def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: @@ -77,13 +77,13 @@ def assert_matches_type( origin = get_origin(type_) or type_ if is_list_type(type_): - return _assert_list_type(type_, value) + return _assert_list_type(type_, value, path=path) if is_sequence_type(type_): assert isinstance(value, Sequence) inner_type = get_args(type_)[0] - for entry in value: # type: ignore - assert_type(inner_type, entry) # type: ignore + for index, entry in enumerate(value): + assert_matches_type(inner_type, entry, path=[*path, str(index)]) return if origin == str: @@ -141,20 +141,22 @@ def assert_matches_type( raise AssertionError("Did not match any variants") elif issubclass(origin, BaseModel): + assert inspect.isclass(type_) and issubclass(type_, BaseModel) assert isinstance(value, type_) - assert assert_matches_model(type_, cast(Any, value), path=path) + assert isinstance(value, BaseModel) + assert assert_matches_model(type_, value, path=path) elif inspect.isclass(origin) and origin.__name__ == "HttpxBinaryResponseContent": assert value.__class__.__name__ == "HttpxBinaryResponseContent" else: assert None, f"Unhandled field type: {type_}" -def _assert_list_type(type_: type[object], value: object) -> None: +def _assert_list_type(type_: type[object], value: object, *, path: list[str]) -> None: assert is_list(value) inner_type = get_args(type_)[0] - for entry in value: - assert_type(inner_type, entry) # type: ignore + for index, entry in enumerate(value): + assert_matches_type(inner_type, entry, path=[*path, str(index)]) def rich_print_str(obj: object) -> str: diff --git a/uv.lock b/uv.lock index f18af84943..8f09a62641 100644 --- a/uv.lock +++ b/uv.lock @@ -226,70 +226,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl", hash = "sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101", size = 132079, upload-time = "2026-09-05T10:42:37.923Z" }, ] -[[package]] -name = "ast-serialize" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/a9/11851c3e02a3fea2ddc9932d1fdc7d2edaeecc0d2e11bc5f2a7fde2b0934/ast_serialize-0.8.0.tar.gz", hash = "sha256:6c37c43e4004dfb42d321ddedc569dc17ff4259296f3af577c9ea46a809bc010", size = 845638, upload-time = "2026-08-07T11:29:02.152Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/16/6e520b57cd8c75914b38c670ad4593d13c22911e4306cc7165dab8b0789b/ast_serialize-0.8.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:3d822605fa7bb326ef868d25fafced7fc660fa46d9b90c02ea86d5e2f5d325f7", size = 863924, upload-time = "2026-08-07T11:27:34.579Z" }, - { url = "https://files.pythonhosted.org/packages/03/e1/48802de9b22a2bcad42ec80601a17e3f69172fe4f590e6311bcc2b323aeb/ast_serialize-0.8.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:2efa40b068197d5efb62655b43baadb842ed71c4958cccd3e8b86a35726f0119", size = 1177662, upload-time = "2026-08-07T11:27:36.196Z" }, - { url = "https://files.pythonhosted.org/packages/38/d4/323438db76bded3a1f3523a3167b8325916b2ddceb2107a330c6ec9fcf4d/ast_serialize-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:db1b957291bca08c7e72f43a12357b2948e20775d970e3fc3dac0aa3160ab725", size = 1167072, upload-time = "2026-08-07T11:27:37.646Z" }, - { url = "https://files.pythonhosted.org/packages/77/82/53c5400b54144b56de8ed7f957fd1ccd97e42482009292ab46121d15f8dd/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdc0d5b18ff8fb364e87923e47c0a91d0d69dbcaeaa274591f7fd26892cc3a3a", size = 1225497, upload-time = "2026-08-07T11:27:39.225Z" }, - { url = "https://files.pythonhosted.org/packages/44/5f/36c07327a8b91303fbf1382c7c3e8a2902072dbe1b9546138a5288e75ff0/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9da7330f3e235bf7da89b8d39205c6350fc0c08a85379743f2df9fff87d6d980", size = 1227101, upload-time = "2026-08-07T11:27:40.799Z" }, - { url = "https://files.pythonhosted.org/packages/9d/48/5adf5c67addc7ddb328122208c6d375a84cf154984f412b4087330a157bd/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3186969ee66a9863b00acc6523ace44c56974eecb348a7ea4b228d9f0b80e19", size = 1424001, upload-time = "2026-08-07T11:27:42.708Z" }, - { url = "https://files.pythonhosted.org/packages/38/a1/70074dd3869d2b0e934f91891d8d6b734361cd3b80f85ca7ece2e668ecdd/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40a57b73731be45da4fa41430c4d5dc94a24b3a4faba7b9e069978c0402064ea", size = 1245545, upload-time = "2026-08-07T11:27:44.4Z" }, - { url = "https://files.pythonhosted.org/packages/e3/be/53b9c0a8a6399950c2e3546bdfab96d2b299d5b114b47eb94fd3c49c4054/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5075b9da3ef807eda752502446dfecea3b381c4900b7e27a5d5f4f899eb39951", size = 1248961, upload-time = "2026-08-07T11:27:45.781Z" }, - { url = "https://files.pythonhosted.org/packages/eb/13/3651d3812548a2bda15e26e5dd51aadb48cf682d0865370255fcf0e367dd/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:293cc1c5bfa741f8e3fbe8175b9c07beee487c9a6fdbb25a5acad9f1df2d30a9", size = 1243877, upload-time = "2026-08-07T11:27:47.325Z" }, - { url = "https://files.pythonhosted.org/packages/21/a0/521f0bf000f675e9312a4aae2c8ba7a992405d072a85c485e08fd59433b9/ast_serialize-0.8.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0910c3442a75216dde0f102d854ba2aaa71d2482e0ee213630b9bf29584fba3", size = 1293903, upload-time = "2026-08-07T11:27:49.264Z" }, - { url = "https://files.pythonhosted.org/packages/b1/7e/402fc902568aa2ee65865a3e151f000db0153da8ce6b1be4c9c349025f8d/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43dd6d596879bb1cb8a12cc9dae7bb10090a39a35883026c24f82488a195619a", size = 1401070, upload-time = "2026-08-07T11:27:50.947Z" }, - { url = "https://files.pythonhosted.org/packages/ff/7c/97d4b66c057f1706fc8be6dd532cc77c988794357c8f4ffdb6adabb39562/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8c9d537f59e936392cfd3597789d1390304dd659efc3c486ce7f40fb6b8a9f53", size = 1502602, upload-time = "2026-08-07T11:27:52.364Z" }, - { url = "https://files.pythonhosted.org/packages/89/6f/72cc3b71562001bba46e898ccfbf1844f7939b3e28912736206102f2e5a8/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f0190a33d7f97c65e9069f7a7f40499eea6b5cbe260c558378109caf20ce934b", size = 1495848, upload-time = "2026-08-07T11:27:53.803Z" }, - { url = "https://files.pythonhosted.org/packages/a0/53/d6f629d1e49308b2f363dae028baa213ec222c9106fa1f7f0d1f7b41499a/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:77308ae6c5cf5264cc0f01a7c556ec77a9e68eb1f61b093534d698139fdc3b14", size = 1556556, upload-time = "2026-08-07T11:27:55.342Z" }, - { url = "https://files.pythonhosted.org/packages/ee/22/340f35dd8dfc6d412d53dc20699ca014b8d228db923e8ed4759c512b162c/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8d53a23f27e1ed3a36b2d26fd2a1a6228c8e85a1ed62ff7cdb44bd610769f20a", size = 1417822, upload-time = "2026-08-07T11:27:56.712Z" }, - { url = "https://files.pythonhosted.org/packages/11/29/6dde5c13fbebc051d3a6df4ec0a6fd1d5359333cc1193f7f609f3410b4d8/ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa5e7cb08f96fed9121f77b224151e41caf88feab9d652bb46c78202b6fbeda", size = 1445153, upload-time = "2026-08-07T11:27:58.275Z" }, - { url = "https://files.pythonhosted.org/packages/62/c5/f473a8ed030f7a0ca24b9849cca184677a50c053867a7b808c2e1289bbd3/ast_serialize-0.8.0-cp314-cp314t-win32.whl", hash = "sha256:fa70ed4dea0bb18b30a1789c77baa701d0ef30c474f2ccabdea61e25623a8827", size = 1063711, upload-time = "2026-08-07T11:27:59.793Z" }, - { url = "https://files.pythonhosted.org/packages/23/63/39e171fcd38ca057c2e1979d5ee81ac7a3502784abe3d83df7454f7a0978/ast_serialize-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d8b3c8eee4c1baef9d4e84d2a59a805501617127be42615cb48970b15b0892b6", size = 1103740, upload-time = "2026-08-07T11:28:01.405Z" }, - { url = "https://files.pythonhosted.org/packages/21/1c/d00762b399e7726d68d0a088cc946e3a4c60f1c6176f557608f672f627f3/ast_serialize-0.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:ac4f0a83c55a9b782f79ad55a5247b7db123c1db405959791c2ef886e9710c9f", size = 1076021, upload-time = "2026-08-07T11:28:02.947Z" }, - { url = "https://files.pythonhosted.org/packages/4c/11/911210c3c78923273a9211a2b6cfc4c8aa723b30dab3e1c8d19afb983b40/ast_serialize-0.8.0-cp315-abi3.abi3t-macosx_10_12_x86_64.whl", hash = "sha256:86b8a1e6d90467345356098b040150e82fbc26d24a7a202224b13dc1f6264ca0", size = 1177715, upload-time = "2026-08-07T11:28:04.654Z" }, - { url = "https://files.pythonhosted.org/packages/77/89/6282881c8587606638db153cbe21e1e0c4d1f3970dee1aa0610a1c62a026/ast_serialize-0.8.0-cp315-abi3.abi3t-macosx_11_0_arm64.whl", hash = "sha256:39e92ff8e8cb45947fe9007174b2950e1fb098e6abd00266a13cd3bcf6675068", size = 1169347, upload-time = "2026-08-07T11:28:06.1Z" }, - { url = "https://files.pythonhosted.org/packages/97/78/a9f846a03a340ff3728c915f23338ca742742f3292700559cdb3ad999b1e/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c85d8d18db5b2dfcb3b7e38a4d600ca35504c0ed8a6f75cd1c811e4ffe248a15", size = 1225916, upload-time = "2026-08-07T11:28:07.654Z" }, - { url = "https://files.pythonhosted.org/packages/c0/15/aba6ef8a988a6eceb6f0359589aac509e29ae2dba67fd9bfd5af0c3f13e7/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9830ff7e764f74d9eefb01170c61a9f0fd2c027dac5fcb72e064decd57d56371", size = 1227135, upload-time = "2026-08-07T11:28:09.504Z" }, - { url = "https://files.pythonhosted.org/packages/94/29/3f63d696ea7c5b8abadcecc3505be51bd900daaccc522ed8322fa5b05a93/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6479d9722a4cd21b578f5478074c41e6169f04811996ec881655560f703a5bba", size = 1425040, upload-time = "2026-08-07T11:28:11.044Z" }, - { url = "https://files.pythonhosted.org/packages/e2/5d/0aac338604ff59df5774d4304307898982252f325ff7cafe31d52fedcb65/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a63bed264e818cd83eec11feed0f50aa162542b91132ef58afebc857182763a5", size = 1246278, upload-time = "2026-08-07T11:28:12.519Z" }, - { url = "https://files.pythonhosted.org/packages/23/ca/9f1ef795bb724719532bd86dbec11e5b66857d3fbe9b6772baec0191a6ed/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d187197d234aa45d6cfa2b096be5f666e8cc2e7eb3722d0ab8926293cf5720c", size = 1250029, upload-time = "2026-08-07T11:28:13.896Z" }, - { url = "https://files.pythonhosted.org/packages/dc/25/5e061372d2ed953b9ba3b9c4f73de3b8e9234cda3f6c088db4686801d0e1/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_31_riscv64.whl", hash = "sha256:2d39a56282cfcc0d8eeea37267c754be59c98d48505c23b1dae5c6011f3813dd", size = 1243575, upload-time = "2026-08-07T11:28:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a8/c1/ae7da218053120635a4ca802366c69f707203641af95372eeb83f70dfd52/ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f7cc5f10386994c0f4844f1e6d6a97127e9b478660eb6dec2b257644f0acab64", size = 1294396, upload-time = "2026-08-07T11:28:16.813Z" }, - { url = "https://files.pythonhosted.org/packages/2e/89/271d1f49c5269fcddcc789ea3f25be401f6723fc1138aeda539f4d05516d/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_aarch64.whl", hash = "sha256:6102f2f985c2e542be85cd857678ec9356fefa792b93cadfadd31139f5696f27", size = 1401987, upload-time = "2026-08-07T11:28:18.333Z" }, - { url = "https://files.pythonhosted.org/packages/55/be/4e7d77fcf571ac7cb5cf7115a20c36642bd7d29473b45dfaaefeb9618f90/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_armv7l.whl", hash = "sha256:3a8660fe66667b76a6e9dccd1d33e66b229fde3b308db991c041609226c005b6", size = 1502904, upload-time = "2026-08-07T11:28:20.039Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ae/ed1de2db7e019d4236fbc164ffa5ef9a6022a300a342bbf142d21b7c141e/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_i686.whl", hash = "sha256:e7266307e5fba39836edb79def8608887af48820508bff3c5f2941e1e04d1534", size = 1496967, upload-time = "2026-08-07T11:28:21.734Z" }, - { url = "https://files.pythonhosted.org/packages/92/89/5fea507fae5c5f18b7dc7f95e5c00956574b8c717b8fd2049c504fab0b18/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca7e6fd1ad845d1cc649dc2ecd499db2f8f46af5bf8da7b70dd858774cc038b", size = 1559041, upload-time = "2026-08-07T11:28:23.194Z" }, - { url = "https://files.pythonhosted.org/packages/42/71/478d69df21b64e064554a68134c94be304270316ca676a94e63c389a636a/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_riscv64.whl", hash = "sha256:2880350b13d3eae69a0d70bc1fb6c9bfaca4dbd0e20ba8cd1aa483080b56ff06", size = 1417367, upload-time = "2026-08-07T11:28:24.601Z" }, - { url = "https://files.pythonhosted.org/packages/5e/2d/8962dc8d5b3a9dc27b36f9db199afa25264c741505469d9ec10ffbfd2ba7/ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_x86_64.whl", hash = "sha256:ab0f9a59f7d63d0d441b56b9a818b273705264352d5115cfee12e940e816d958", size = 1446178, upload-time = "2026-08-07T11:28:26.152Z" }, - { url = "https://files.pythonhosted.org/packages/4f/22/14d2ad4fd1d1bcd0dc687ca268e0630069f45162496260c0efb70ee0ea72/ast_serialize-0.8.0-cp315-abi3.abi3t-win32.whl", hash = "sha256:0485a25ef519c62e749ee3c1ad8070e591b380d67226349eb5a70b228dc1ac4a", size = 1063811, upload-time = "2026-08-07T11:28:27.864Z" }, - { url = "https://files.pythonhosted.org/packages/18/1d/84a327c0202a41aa5fdba3ade33904d6d8f3b9e6806fa83568d835395850/ast_serialize-0.8.0-cp315-abi3.abi3t-win_amd64.whl", hash = "sha256:bd84d60bca7079e741be4ac5dbe237751a59d7f6f9f0126b11880d63822cbe16", size = 1105518, upload-time = "2026-08-07T11:28:29.691Z" }, - { url = "https://files.pythonhosted.org/packages/8c/92/74556dec52fde85a2ad84ed159991b916241043788609c15d8b77e14570b/ast_serialize-0.8.0-cp315-abi3.abi3t-win_arm64.whl", hash = "sha256:057769b5921336eb2d9124f2a731b42ed05ffdac559b840dbdf6f3937cf153dc", size = 1076319, upload-time = "2026-08-07T11:28:31.282Z" }, - { url = "https://files.pythonhosted.org/packages/d1/5d/c650b1f2cc1e75193358da95a080261422e8cd10b66d7370b1688c9915c5/ast_serialize-0.8.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:a02cbed7d8bfdcdee88edaac12bd50d53d9953aaa2e1852ef078625be5f1c0b5", size = 852914, upload-time = "2026-08-07T11:28:32.929Z" }, - { url = "https://files.pythonhosted.org/packages/d9/e3/6142e920fec6ef7bccabd8c24ed8ed99f8bdc6cb8b065e1df7c6a3b2d667/ast_serialize-0.8.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e1bd223df0f6c96b396975fa604cb33bce53d9b4a0185490be4c4a289f7c9c87", size = 1184007, upload-time = "2026-08-07T11:28:34.654Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e9/6e8be8df02b35d85e2b8809f7f1cfa290bdf5882b55127a539d049482db0/ast_serialize-0.8.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ddd3b61f45c132da66c5476b281891e08c1fd87fbdabe8a6973e1622efc85f06", size = 1177588, upload-time = "2026-08-07T11:28:36.318Z" }, - { url = "https://files.pythonhosted.org/packages/8c/80/7e0fd2e2e2aba257820db4a8657c4c356844d36b914b20a4af294bcfb902/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f9caa63fad8241257ae401b5ff0a64026c6adb36b8e86cbe8782d9ea505daf6", size = 1234575, upload-time = "2026-08-07T11:28:37.772Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6a/3bae0af06f9b1bae3001c44d64215f5b567877e7aae9ffd45db11c3a7647/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3926fa117b5e65019853a2969966d11c7175af377a3425991f3fe73784412405", size = 1236015, upload-time = "2026-08-07T11:28:39.14Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c4/ce2d41a1bc22508e82618901f7e10f2a5e2f9556553fea90624daf9875e2/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:485f1113af805e9e170b95ef993ca3fbd4f89c04bab25c58b4fc632d854801ab", size = 1432808, upload-time = "2026-08-07T11:28:40.664Z" }, - { url = "https://files.pythonhosted.org/packages/1a/90/f5058f209756dd70e958b7538aaa82d25d24944baf9ec8ae6f27b06fcacc/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccebbed24f1281062d5852353c72c47502955926cfcb8345ffb3a44d87ff3d3", size = 1256251, upload-time = "2026-08-07T11:28:42.223Z" }, - { url = "https://files.pythonhosted.org/packages/bf/32/7f77ea87fa0836daab706ed5cb7f903bb25fa26a77439011aee626af11d8/ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:252f883290d1cdb728eb7fe1d9a7221b88af5a329aae0bc91ddee4dafb820331", size = 1258574, upload-time = "2026-08-07T11:28:43.751Z" }, - { url = "https://files.pythonhosted.org/packages/eb/5a/75b82ad2725b5e8e8c742732f9e76c6738a292d0709e1f60d10a973730b4/ast_serialize-0.8.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:96abc072ad29db8d02194afd47d68987322622787daceae82398d7b69f3ba2e6", size = 1254075, upload-time = "2026-08-07T11:28:45.28Z" }, - { url = "https://files.pythonhosted.org/packages/4e/54/8c20ed4eea805516a3fd23dd4a721ce28c64f50f0e4b359969f60a8c97a6/ast_serialize-0.8.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9118ad3e369727060b2696fc4078f250ecffca4248ba87f537f55cea9f9dce06", size = 1301018, upload-time = "2026-08-07T11:28:46.851Z" }, - { url = "https://files.pythonhosted.org/packages/cb/5b/9f14430f12fe830b656fb38f8e2e05ee13b02a88967660bef46af0ab22a8/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f359df4bd921918af8bebd142a376c77511d7151cc8ba852760b587b5a4a54f3", size = 1409951, upload-time = "2026-08-07T11:28:48.312Z" }, - { url = "https://files.pythonhosted.org/packages/2d/3d/084882eca93c842bd4262591a071ec7f825340644035e51501208cc5a8d4/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:e94f9121d13fa36cbf21314783c77d05ae3a0868decd18cf5233fdcc6de49ac8", size = 1509544, upload-time = "2026-08-07T11:28:49.847Z" }, - { url = "https://files.pythonhosted.org/packages/ce/73/ea84852096c2036c61cc0b2f97b90242207419f534dc671060ee1c8e05cb/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:54f95b486018d262bcb387a9afd96f0da74508b442762b80c769454a6fbb3ee3", size = 1505671, upload-time = "2026-08-07T11:28:51.239Z" }, - { url = "https://files.pythonhosted.org/packages/cb/88/287b9a5300c1f2f651d259f670931b63110adc265b7613c885b44c5bc53d/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4c38b915511e32bc718c49dbce98ff9af36bac0ad6a604f58000cd5e3aecdba7", size = 1563685, upload-time = "2026-08-07T11:28:53.112Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f3/1bc3a79afcf0c2a8d2c37182d0d659d1545a9d7f7f6dc9cf3e63d6c17135/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:9a2ef9cf12f2de4f1028c42c1dd7d775255e0fb3e5bb48896c97e35ef52366fe", size = 1427977, upload-time = "2026-08-07T11:28:54.418Z" }, - { url = "https://files.pythonhosted.org/packages/5c/cd/440c798957e14e31776bfeb024d8fafe0bb1d5b89c51c2f067e69938f7b0/ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f18048fe9f6dd266bd577cdec48bdcecb74faaa01fe941324435483b013ed2a", size = 1454335, upload-time = "2026-08-07T11:28:55.968Z" }, - { url = "https://files.pythonhosted.org/packages/4f/4a/587eb36dcc240a54c8660f599464516b469ecad96f0dbdb6bccbedb50745/ast_serialize-0.8.0-cp39-abi3-win32.whl", hash = "sha256:31883542dd6c94d178f5db3d32fbd69c5eb88b3a7c018e7ac8cc0c45195ddbed", size = 1068858, upload-time = "2026-08-07T11:28:57.541Z" }, - { url = "https://files.pythonhosted.org/packages/5f/a4/3e887bbd92164e183cb6e412c6a3e9198ddd446d7fe405958293ef5ef49c/ast_serialize-0.8.0-cp39-abi3-win_amd64.whl", hash = "sha256:861794565b06337005c1447ef23103a3d5a627d08bdc827870d00d0b28ef5f51", size = 1111839, upload-time = "2026-08-07T11:28:59Z" }, - { url = "https://files.pythonhosted.org/packages/25/6c/b400476d3ceba681ab929787edc9554f6d88fcc69435eb681b00fc0457a5/ast_serialize-0.8.0-cp39-abi3-win_arm64.whl", hash = "sha256:b2a5978662fd4db463dfb4b974d2b10ac6430b98f5333aabc7051909df3561d0", size = 1083655, upload-time = "2026-08-07T11:29:00.349Z" }, -] - [[package]] name = "asttokens" version = "3.0.1" @@ -1140,136 +1076,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, ] -[[package]] -name = "librt" -version = "0.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/9b/356320fbae2ac8467e21c5e73e1389c80468e4998c62cc7d3536cc51b614/librt-0.15.0.tar.gz", hash = "sha256:4e66cbe84437497d951b799d3e1551291b6fb3d643820a7014b3655d57a59162", size = 214338, upload-time = "2026-08-07T10:49:42.663Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/12/e2e9ca532cf5a0e08c9489826c4a35c6958c92ba0313fda70e8c6c3912be/librt-0.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1a49adf16a7c9d9646816c2946135527197b6fcf4347c7b8b761cf1bfbf4489", size = 148673, upload-time = "2026-08-07T10:46:22.569Z" }, - { url = "https://files.pythonhosted.org/packages/6d/7c/02005e23478bd5950618d9712e0fd2b4c511657857f3efd8ba6a5feabcdd/librt-0.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81a398f45b45a59200e13cd5ad1ae1d3f44334de98b148331afe2cdfee701c52", size = 153547, upload-time = "2026-08-07T10:46:23.931Z" }, - { url = "https://files.pythonhosted.org/packages/a0/90/d8848a735f5642077fc4b3b4bebcdb08edf10178e3add45597f5201a368f/librt-0.15.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4eafbaff06b9563f8b1c850621ce51605de05208e09d4d71ce490bc972b7b9e8", size = 494355, upload-time = "2026-08-07T10:46:25.122Z" }, - { url = "https://files.pythonhosted.org/packages/e1/0b/8604f41ea02feace490e9e405a338a15f9905369f55b239a9ce31c946f24/librt-0.15.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:b0411b4066db926b80258c60dcb0e6db4c9cee312eab45b7e8866b17ddf9ada1", size = 485459, upload-time = "2026-08-07T10:46:26.447Z" }, - { url = "https://files.pythonhosted.org/packages/a0/ac/84153bda1ce0da609182527ab92b40d961809e544eefdc5a1c2422971416/librt-0.15.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:febb1ce6cac545a54e6b769982824e955a700fdd9fbf3a08a3d82c990968b57d", size = 498398, upload-time = "2026-08-07T10:46:27.701Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3a/5ca6cd282b2c244bec8ec84102e09773264e9c02891d56ab3a8f0e4d7083/librt-0.15.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b230acc1c3bfe2d6f2627ba2b95dc92e58aa494600e9722d0e6ccbc931e59702", size = 515474, upload-time = "2026-08-07T10:46:28.9Z" }, - { url = "https://files.pythonhosted.org/packages/73/d3/bd34110234779eb843c6ed66aba7c9b2091d3dd85989f1fb9922f564cb7a/librt-0.15.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6da110e5f314c19ab8478464d02ae18808ae73d522c15260fa4918acdcd64da9", size = 509484, upload-time = "2026-08-07T10:46:30.124Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/43c3f7f071d71631a7daa3b835ef2168ea39f20692d81464d4e47fbaa6d6/librt-0.15.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:eab9208b00ca55bf75983ec99f7bf13acc746a36102e98953addaad7f7ea1e1b", size = 532534, upload-time = "2026-08-07T10:46:31.511Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1c/b854adf036ea817c40408873a5b794d65a91d9f0f39826f2ad2a2d5d7f48/librt-0.15.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6c013cd3a1721e69e14380ada97eaa4b7b0cdf1c6b96fa765d4ea47c875088db", size = 537087, upload-time = "2026-08-07T10:46:32.734Z" }, - { url = "https://files.pythonhosted.org/packages/25/5c/c9a890e244e7dd725d3bd8b560e41f0aec787eaf343b46956a290ab7b841/librt-0.15.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:567b1c430f8bd560e689421468278ac5941bab4a05303b5d95b6ae10db03f451", size = 536575, upload-time = "2026-08-07T10:46:33.965Z" }, - { url = "https://files.pythonhosted.org/packages/5f/c5/c8e70b60b704299555f55db468eb46b1c81bfc60201ffbfe20407d89870c/librt-0.15.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:29c4cab9df457b19672c39be7f384ebb2bc925c4e2684b8780c222b43eb36389", size = 517142, upload-time = "2026-08-07T10:46:35.577Z" }, - { url = "https://files.pythonhosted.org/packages/56/d1/767a90c41f5d381b3195bc88ac0ec4afda35777c9c781e1f9848fedd965e/librt-0.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bccbd8e5b0bffb7106cf18eb1baa3d7194b1cebb3b4b1cdbd4bdb19382a6ee6c", size = 558714, upload-time = "2026-08-07T10:46:36.829Z" }, - { url = "https://files.pythonhosted.org/packages/f9/b4/3c0624b8dc8301ab808f2b3a910995bcabe28df070fb9a0e5505ae997dae/librt-0.15.0-cp310-cp310-win32.whl", hash = "sha256:8ae493ed5f659a7761c43d42f183db514536073ded9bcf671d2d1df47e29a07e", size = 104426, upload-time = "2026-08-07T10:46:38.594Z" }, - { url = "https://files.pythonhosted.org/packages/31/98/e91c0382304bedb2db9c6801897319a9dcb68daac5e975819b562362f20d/librt-0.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc25fb356d0c7810bb49ff3df908ad1fda6995d660ab099ded69244ed7ab6053", size = 125057, upload-time = "2026-08-07T10:46:40.052Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/06790ced2ac7117f890c21bda43c39c958ec82aa665c0718e821d33ff939/librt-0.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:823b92cf3c18ecd08afc70c42473888b41b6e8ef5046f3b82c05c154a2fa3d22", size = 148039, upload-time = "2026-08-07T10:46:41.165Z" }, - { url = "https://files.pythonhosted.org/packages/e7/1d/8e150b7fc449a1f33c8a760965cc1f43b14fc1577d9d0b50ab2701420e74/librt-0.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c70bc1b602cf59917e8f0c7a2cbc8bcc6fbc14d5486136b00707a79619121d63", size = 153067, upload-time = "2026-08-07T10:46:42.418Z" }, - { url = "https://files.pythonhosted.org/packages/51/87/a162bc5a66a35599dc619ecb215145f4de7d68e886b479b6d12593139f7c/librt-0.15.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:814ff83a25b5fce8b9c80c4dd803153fb5c5599fc74db9e022466938368957ef", size = 493087, upload-time = "2026-08-07T10:46:43.657Z" }, - { url = "https://files.pythonhosted.org/packages/e5/3a/aeea1fc620cf48060d3065b37614edbf97043c099d0f50782bc8ca61d897/librt-0.15.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:57f5eeb6ad4c180de583b1038e61fe5fbd9796bb69a8a1c1a0c7ddbec4c8c60f", size = 485608, upload-time = "2026-08-07T10:46:45.038Z" }, - { url = "https://files.pythonhosted.org/packages/52/ff/fe571ad416f0856fd0d5578ffc2e6dc531891e586e36b647bcf50569cab8/librt-0.15.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82909c8f7eb9952656b65d3147afde4cf8e6d5a991eebc86418b5e65843b0ab8", size = 498723, upload-time = "2026-08-07T10:46:46.35Z" }, - { url = "https://files.pythonhosted.org/packages/0f/e1/7a65eb5dedb1f00aebd948cdd8e17add48bf066cab3514e9daf84ab45a6c/librt-0.15.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f779070399f991400fc451719e0ea388eb7de313388bada2c127a35de05f798a", size = 516002, upload-time = "2026-08-07T10:46:47.599Z" }, - { url = "https://files.pythonhosted.org/packages/5f/45/59832b0ebfbd08c2742e6ece372ceb53f18bf1faef5d33c8daf3abebf749/librt-0.15.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bac89069bc496ebdf4f79ebb57bbd10d0b214c8454225deb672d91002bd17e18", size = 508607, upload-time = "2026-08-07T10:46:48.873Z" }, - { url = "https://files.pythonhosted.org/packages/ea/0d/37fa73f3b43ebd8259f91ae9102a15e5a54e65d581e48dea72df3e81d7a4/librt-0.15.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e0d00c708fb2f5822b152429b1ac80a58dbbbc3f6c232c4d13a3f7fcf2ea5b4c", size = 530422, upload-time = "2026-08-07T10:46:50.45Z" }, - { url = "https://files.pythonhosted.org/packages/26/02/e046c6fe7a5881ac34623242192f484426ba8a75595fd18f22c53a3f530f/librt-0.15.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6c6624fe268625869485553dd7cc1daf30d22558215bb2a4ff16f67a9801a31a", size = 534303, upload-time = "2026-08-07T10:46:51.693Z" }, - { url = "https://files.pythonhosted.org/packages/95/32/d5e6d861ab0366f3edf74f887ab0c9eb9f535aaf01d32b80b4f734daa179/librt-0.15.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f56b397858a23dacf35ede366ed2212fdc03a6a57a1ad36468ad6e9dc5fac091", size = 536084, upload-time = "2026-08-07T10:46:52.951Z" }, - { url = "https://files.pythonhosted.org/packages/2a/de/d69d725513fe53fc90c6d7a1f86e4428939bad2fb905b17fe4c18d413dde/librt-0.15.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4388184646efe2054911c5b00a1077d6d1ee86a95b7e8ba96dc7850a809f3f40", size = 514307, upload-time = "2026-08-07T10:46:54.194Z" }, - { url = "https://files.pythonhosted.org/packages/36/93/f8aded0d6682b4f25820fa86e0690f87f01df9fd7bd09ddb04d9167ad021/librt-0.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:97335f59082f9fe2ce6c2a9cc6433a0114bbb6cd4d5c09dd76c95c68b9f9a8b0", size = 557686, upload-time = "2026-08-07T10:46:55.443Z" }, - { url = "https://files.pythonhosted.org/packages/74/09/ffeb6bdeb6cd862b4272fddc8ad05f938dd25d020ed517e631813917d80a/librt-0.15.0-cp311-cp311-win32.whl", hash = "sha256:83380ffde38062a2e9bb55d83e74474f6614665528b98a6928720fc006dfffbb", size = 104917, upload-time = "2026-08-07T10:46:56.605Z" }, - { url = "https://files.pythonhosted.org/packages/96/28/7e2313a3ffbf0b4de7ba3da58a09e488507b4bd1ea2b5e69378354a23415/librt-0.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:f75720477ee05d509a310e856cacc8d909adc182f7b91193c207bcc26d7ee6db", size = 125886, upload-time = "2026-08-07T10:46:57.729Z" }, - { url = "https://files.pythonhosted.org/packages/39/9e/04b8c3cde014ef255ee785730425268354543acc38902093a40afa0dc164/librt-0.15.0-cp311-cp311-win_arm64.whl", hash = "sha256:256237037a3ab001ae8d9803b2d43562a4c3aa38739843694349e4d5ebb0fd56", size = 111885, upload-time = "2026-08-07T10:46:58.787Z" }, - { url = "https://files.pythonhosted.org/packages/ba/39/99c25030e782bdfb7a21be8c05254806a2e4bbb05c8d50c2a2130acbfa05/librt-0.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e87bc679f86a99aa3b26e3c78eeb821a247c9a28eae48eaafcc32c3bf4c3bb9e", size = 151021, upload-time = "2026-08-07T10:47:00.057Z" }, - { url = "https://files.pythonhosted.org/packages/14/43/f4b1bd1b2888798a1409808889a25ea1ba49eaabce7d681ed27734c2df9d/librt-0.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71599e011ac880e8e45d46047d714871894c7d4ab6f25626f8d4f89da21f368d", size = 155267, upload-time = "2026-08-07T10:47:01.311Z" }, - { url = "https://files.pythonhosted.org/packages/0c/db/3ad9c965c72f1e1d6beeec44ec10a54e17be8ae042fbb4baade16cbadced/librt-0.15.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c802434092b769b1d613ed2e13fac15fbfce1934a74bd10283b03c0fae231cd1", size = 503136, upload-time = "2026-08-07T10:47:02.45Z" }, - { url = "https://files.pythonhosted.org/packages/4b/07/5888a6d76acd62ebce66c61b74d94e9370b9c32929f111e487bb6546f8ed/librt-0.15.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5500eeae393a184d14e1f35645962c27129d20c81afa4069e6ef826ebc2b3aaa", size = 496670, upload-time = "2026-08-07T10:47:03.675Z" }, - { url = "https://files.pythonhosted.org/packages/29/39/ab57cc2f5b276156da02bb7f5a8921bada1cb1993ffec99acf811c602c23/librt-0.15.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6ecfc32dfb46fb7b565bcd6abf9412acf978775a998273d22888a6d7953730dd", size = 513688, upload-time = "2026-08-07T10:47:04.981Z" }, - { url = "https://files.pythonhosted.org/packages/a7/b9/bdbb0b648b5c2befb031f4c6f3b1dd857415e8fb492a25a3c764a6681e6c/librt-0.15.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cc46cfd15022e35084355478c9ac809d90b1152222706ac9a7655ec21df6fa", size = 531904, upload-time = "2026-08-07T10:47:06.211Z" }, - { url = "https://files.pythonhosted.org/packages/93/26/473c2e4b6c104e9e58e27ce95fc8005c8bd4fc36cae4f254371125a92db8/librt-0.15.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5f51401d102c885b9ca509e62c79b1dbff286e1b9b047fde6f763780789356d", size = 524427, upload-time = "2026-08-07T10:47:07.592Z" }, - { url = "https://files.pythonhosted.org/packages/26/60/03b3abb82b41714671b907bf6989b228e31e6a8af52dec82b5b0728dc250/librt-0.15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cc30523e3f1a23fb7511cc659834a0d01a1042bb9de359bc1c131cc4ec6c9656", size = 543155, upload-time = "2026-08-07T10:47:08.866Z" }, - { url = "https://files.pythonhosted.org/packages/f2/0e/9bb1f0a4affbd0a1888f4f79dc03ed2a299d9a2c26c59ab2a97dcbf11903/librt-0.15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:59fe030d8ae4a57e3fb7756bf35a858de74e04066fc8555c53d0af979132af81", size = 546890, upload-time = "2026-08-07T10:47:10.327Z" }, - { url = "https://files.pythonhosted.org/packages/dc/84/6937a280d461f7de6e031ffb02edc2b7c3c90d49d630565ce8ff27cbc5f2/librt-0.15.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a6526a2a956bbb1e4ae3568c82e650fc99119c66bb011ea60715744955a2b4d", size = 555163, upload-time = "2026-08-07T10:47:11.798Z" }, - { url = "https://files.pythonhosted.org/packages/bc/95/2a2853c1ee014bf102116e7f897a04beeaeb2461b45b79af98bdfb95f1ef/librt-0.15.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:85ea21ec6730194d67156b0e0b5430ccb1d61f8b8b907e39b37f9812b74a13f0", size = 535812, upload-time = "2026-08-07T10:47:13.279Z" }, - { url = "https://files.pythonhosted.org/packages/c9/4c/cf9601c1b4c5f09280acd5d83abdb2e68527a2be8257136eb42304218622/librt-0.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1e47b8ba865d7ede071a91a7163073bbaeb72541f1ef8a07d512c45c7b5007f2", size = 573688, upload-time = "2026-08-07T10:47:14.727Z" }, - { url = "https://files.pythonhosted.org/packages/47/6d/9ac7cbec46189a7625af4b5acbd25f10d827f4141b2002181848c8418923/librt-0.15.0-cp312-cp312-win32.whl", hash = "sha256:a5207ec414d1c4a2a7231b2086970dc036f94293cdf338190984958a013a42f1", size = 106138, upload-time = "2026-08-07T10:47:15.973Z" }, - { url = "https://files.pythonhosted.org/packages/38/d0/2ae99c83be86ce23f925ac1aeeedc777e97f427c4a8d190c70d0a16e9a87/librt-0.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:73b30cfa976659b3917c8f6153bdb0591c6a9ec6583599fd24a689b690622022", size = 126974, upload-time = "2026-08-07T10:47:17.049Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ef/dd24f9635c730b86b87587967dda7516b1845e8b17684603d31607fed598/librt-0.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:a54cf9e0ef47b96af580849db5471142200568ce1e02cbf416addab551369570", size = 112292, upload-time = "2026-08-07T10:47:18.222Z" }, - { url = "https://files.pythonhosted.org/packages/e7/42/467b53a601b406ccd7b97c1fd54b59cb34f9185ad5ce7e9d5c3c4e8961c8/librt-0.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:db13ca398005abcbe538deda87b686d9bd08b7001cf40c4c06b444960ae10a26", size = 151029, upload-time = "2026-08-07T10:47:19.312Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e6/36c2299b7a94b84fdd01220d8a777a71be5be0925bb0dbdf71c0a06a34d9/librt-0.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa1f1995789dca3698bc550aaceb09a51bd5df0a057ff84ff15296cd1975b801", size = 155194, upload-time = "2026-08-07T10:47:20.398Z" }, - { url = "https://files.pythonhosted.org/packages/c9/b6/ed5071f9325845e670bd36012757419767fbf56af77ed483077b9e4db541/librt-0.15.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55456ea87d8df21808446d03817be2f65e20391c1c615d9187440dff28cd08dc", size = 502568, upload-time = "2026-08-07T10:47:21.652Z" }, - { url = "https://files.pythonhosted.org/packages/7f/81/6450c67c3615d87704bcbc21323fafc69c799b06a044c447529f725d4b01/librt-0.15.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5a86a5a08c2235316bdb359d5dbb6ce0abfca7fac06363103e2c5af571d92f95", size = 496153, upload-time = "2026-08-07T10:47:22.925Z" }, - { url = "https://files.pythonhosted.org/packages/e1/d6/5f52b722bc75076954b3bfd49be15ea362df4d580c6fb315d0f617100d30/librt-0.15.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e56b6a368529bed262da40ce13f8fef590db0479819cca84f16a1f01ac356d0b", size = 513336, upload-time = "2026-08-07T10:47:24.213Z" }, - { url = "https://files.pythonhosted.org/packages/8d/e2/c08fd1d36ce63ea5a12b85c5d37f4550b5f86a692167e41e5a74222607ae/librt-0.15.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:234d8d394721fa0d786af15ebf1f3fb7f3ed82fd1cd0cde45c2f247b5d4281d2", size = 531661, upload-time = "2026-08-07T10:47:25.507Z" }, - { url = "https://files.pythonhosted.org/packages/3f/d8/d9482fcbeb177b9eb87bb3899eeb3b42be690313c652f9e146b1d0681fb2/librt-0.15.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d8363d7accb0286ac3a0e633f396e93800dafb8150494505daf9515bbda591f3", size = 524487, upload-time = "2026-08-07T10:47:26.79Z" }, - { url = "https://files.pythonhosted.org/packages/10/cc/075171517b41f861753034fbb151b42cfc83bcc853849f24f5e66fd60ccf/librt-0.15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0f0ee3644d951f31055ad07d77d92520e84505dd7a432cc4cd501dd70ee06785", size = 543201, upload-time = "2026-08-07T10:47:27.999Z" }, - { url = "https://files.pythonhosted.org/packages/b0/03/42c2330f37eeb475b6affeedd06518f60035f323af3a839335e3fc9fef2d/librt-0.15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2cfd1a81a648806e6a7717be4cc4d1bb392fa229752bf8444ba365e381e984d6", size = 546467, upload-time = "2026-08-07T10:47:29.396Z" }, - { url = "https://files.pythonhosted.org/packages/57/1e/1ad4c5638f7e64d8560328bd25c54b409a661bdb6ff254b38ff90744288d/librt-0.15.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6cd22c9da0d866558e46a041f1cc0c2bbb26b61b137b2347fa834c332e1d101", size = 555139, upload-time = "2026-08-07T10:47:30.815Z" }, - { url = "https://files.pythonhosted.org/packages/49/41/39fa7d15db1204cd1cbe6514680fbdc243adf754a0885061308f43afc013/librt-0.15.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6d5225ef8801e4ea5e482fa9b5dfb891dd9ef6f6d870f1f25d449ca2c70ac218", size = 536050, upload-time = "2026-08-07T10:47:32.222Z" }, - { url = "https://files.pythonhosted.org/packages/1e/88/c6dcf0dd8e26dc0c9a499a2abab8646c86dcaf9ecea9524cb46d3686331a/librt-0.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d28a05796b99f749bf8794f17ba9ba1612d0076b802e9cfc62c554634e9ce3b", size = 573700, upload-time = "2026-08-07T10:47:33.527Z" }, - { url = "https://files.pythonhosted.org/packages/1b/9b/ab54c71a7918a7c34fa5327fb61390a77446a07a146fbfb1165250a61035/librt-0.15.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:2067ff438048cead9d223ca5675bae2a25e520a7c3e6c1498bf9c6892d22caab", size = 82194, upload-time = "2026-08-07T10:47:34.835Z" }, - { url = "https://files.pythonhosted.org/packages/8d/b2/4f9a243bb892395f3becb80789ade13771701091f9f07ab8230247953ba8/librt-0.15.0-cp313-cp313-win32.whl", hash = "sha256:1cd3b721f24c206398b9e26da3c3a9c011e6e89d06f318ba8ebefc30f1003890", size = 106231, upload-time = "2026-08-07T10:47:36.251Z" }, - { url = "https://files.pythonhosted.org/packages/bf/af/64aff4885a40b93132382f2c314647d722574605416504379184ef3045ea/librt-0.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:f395a4a9a03ac062dbe9a9f82e0c720502e590a38feee6a757bc82e9c63afbd8", size = 126996, upload-time = "2026-08-07T10:47:37.453Z" }, - { url = "https://files.pythonhosted.org/packages/27/83/335bccf6c7cb9028cb0b54aead27d9ece3f01f83bc6baa2abace5da655c1/librt-0.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:0a15cb554761247d84a3ec0cbdf4078d70725384f0e4662c0fa3b26266eb60ad", size = 112188, upload-time = "2026-08-07T10:47:38.729Z" }, - { url = "https://files.pythonhosted.org/packages/a8/93/949053fb462eecc4a9a5ee770a81f4b40be7b79538b245545d4aebc6b58b/librt-0.15.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f5de7feedc56337a088eb15cd9fafa9938367362221d8cc62c642b7f94821993", size = 149833, upload-time = "2026-08-07T10:47:39.86Z" }, - { url = "https://files.pythonhosted.org/packages/61/ca/8281aa6cd560a3420e4497729f6b704b53be3eeaaef82d5aeadddaf7441f/librt-0.15.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c0eb900c0e91f4aebe680845242e614f1864edfd44106380d0752ac29522bf8", size = 154088, upload-time = "2026-08-07T10:47:41.065Z" }, - { url = "https://files.pythonhosted.org/packages/dd/02/1a1662dceaba6a086360891448d5ce9a7d3555976cae59a31a39d744b9c7/librt-0.15.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e8c9a650a188e38bac005048cbe6342e81407782944d01934540ab75e417df21", size = 494215, upload-time = "2026-08-07T10:47:42.388Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/99211619dc656370a3740c33d2b0b6d5a3fb1e73689314f6ed477a397dc4/librt-0.15.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:92bfed8deec93df30286b9fe9e3b1dd17329cc076a192b4ee5ec223841d54953", size = 491173, upload-time = "2026-08-07T10:47:43.683Z" }, - { url = "https://files.pythonhosted.org/packages/d4/aa/5448d0b05f4579b635d3899176817ebf561af0e57bacd425b5b1887264c1/librt-0.15.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ec4b19788f835711a2072f9dbe6b03b3bf32ed1f0fb30cf399bdd59d9f0c33fa", size = 505512, upload-time = "2026-08-07T10:47:45.314Z" }, - { url = "https://files.pythonhosted.org/packages/95/82/01940e40b83c43a546c4a3c896cf34ca272a9690899d55914e4827b3dcce/librt-0.15.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4c7bacb70930f3d0a56f4ecf1be474a1f0d941b01dd73b756f3c256d42cb879", size = 523073, upload-time = "2026-08-07T10:47:46.66Z" }, - { url = "https://files.pythonhosted.org/packages/88/fa/759c0030f3ee371439eb26de34fc745807caf0abb878af7af4b8b7c3dd3d/librt-0.15.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3e79f05e4a08b4d880342673312bbc895b56df7765605796f15902eb5367d3ae", size = 515080, upload-time = "2026-08-07T10:47:48.319Z" }, - { url = "https://files.pythonhosted.org/packages/0b/27/894e072228fcb159703c655da69f8cd10dbed489c36e3df7dd032a2483be/librt-0.15.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a417149c0cba4d50b61e992e5a15e69eaf96746609b461cc4ed168aeef6b79dd", size = 534164, upload-time = "2026-08-07T10:47:49.875Z" }, - { url = "https://files.pythonhosted.org/packages/98/a3/0078e91c1f36f8815db17827de15650b9a3fe56c55fbf998c854b34e40d3/librt-0.15.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:da7a94d6a3411f579d72aa3e3bc5fbca7ed4549f3dbd7e5de3aa567333374285", size = 540616, upload-time = "2026-08-07T10:47:51.408Z" }, - { url = "https://files.pythonhosted.org/packages/86/33/81a29b796dd52a45e9ef7974c7732926e8f10f15b8d2be505665979f896d/librt-0.15.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:856f743ae607f2c1380eccb566c0038a9fb3eabf0fc2be2704d76d9f73557239", size = 545890, upload-time = "2026-08-07T10:47:52.818Z" }, - { url = "https://files.pythonhosted.org/packages/05/82/8be1baa1350e5d30cfd70ae79d0a6f4dc5862ef47f7bb2808aabc9bb86e5/librt-0.15.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:779a6e7c894737e5983e7790a9c78c4000c30e23c9aada08081bdbea53b0fa60", size = 523287, upload-time = "2026-08-07T10:47:54.165Z" }, - { url = "https://files.pythonhosted.org/packages/c6/4f/d1be6a01a35c20ef734e0e44113f87d4af756a9354a89dcfbe3b4f8af5e1/librt-0.15.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:96bb17dbe8bab3c0954fbebfc69ed395599de75b6bbc35e3270a878e15d4dd65", size = 565868, upload-time = "2026-08-07T10:47:55.566Z" }, - { url = "https://files.pythonhosted.org/packages/67/88/649cfa33f5825927b160610f670bdab012a64d627eddb94fa795ea4292fd/librt-0.15.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:7220697efaa6e5348fc3d18ee7f8563d4bfecd9872b37ffb915bfc1d08840622", size = 81619, upload-time = "2026-08-07T10:47:56.886Z" }, - { url = "https://files.pythonhosted.org/packages/22/31/8e88a8d5e48fc8d1a817787fb6811dfff6499acd6c8683dd83934aa6ede0/librt-0.15.0-cp314-cp314-win32.whl", hash = "sha256:f54598964d357b1c5ab77cf5d92f21e598fe0e23cdbe9618480807f81b4eba15", size = 100138, upload-time = "2026-08-07T10:47:58.093Z" }, - { url = "https://files.pythonhosted.org/packages/80/92/20fd6c4b6a1b1a564b076d55cd3d427d8428217d7638dc25a654cc4791d4/librt-0.15.0-cp314-cp314-win_amd64.whl", hash = "sha256:3ff5893a2c23d886aa9ce786de5ac6ddc74aeeaf90743682b74d920e117d2e28", size = 121258, upload-time = "2026-08-07T10:47:59.564Z" }, - { url = "https://files.pythonhosted.org/packages/fc/28/6af430b44d9ebb897b865a3c363b6dcace51357be2347cc0f8f869656a86/librt-0.15.0-cp314-cp314-win_arm64.whl", hash = "sha256:3722a099730704c9a3d70c879fc0f51daec25fe5f1555672d97bc595abeafb95", size = 106467, upload-time = "2026-08-07T10:48:01.097Z" }, - { url = "https://files.pythonhosted.org/packages/7e/aa/b42bb798942ced219f6d63b27e07f91237887a8d0bd0921666db79a13790/librt-0.15.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:38c0c7d4b6fc06c3324b3f9162c8391bfc4fd9dde53afe1033ce7edb48d5a714", size = 159523, upload-time = "2026-08-07T10:48:02.442Z" }, - { url = "https://files.pythonhosted.org/packages/75/03/1b53cd4ef904e73b1d828a5f90143bf94a2967d7cfff0b9ccf93e12aa9b4/librt-0.15.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8b2fdd7ead3c995c37940a790690660d0ca006c302db26cc51933f6766866fc3", size = 161638, upload-time = "2026-08-07T10:48:03.725Z" }, - { url = "https://files.pythonhosted.org/packages/ac/c4/9f9c9fba097d49e9e694c2b4dc331df31884645ecbc58a93b4b5fc69d2c5/librt-0.15.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2fde98cf1fc4bac144ce23c2c4c017b924ba714509ea9334977b0b27050c837d", size = 701795, upload-time = "2026-08-07T10:48:05.135Z" }, - { url = "https://files.pythonhosted.org/packages/4c/05/0966840bda0380c8ae167b9043c6230202941cc90ea29c48e096964c765e/librt-0.15.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:e3b461183c5fa7681b48560f91515f53a953122fb30c71e07abc67d7ddf58c38", size = 682147, upload-time = "2026-08-07T10:48:06.555Z" }, - { url = "https://files.pythonhosted.org/packages/18/af/1c47ca573c30ea47d195aec26133af522fea1104afaace028d7b32247ea8/librt-0.15.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4bbcc257e3babea20a91715c361b24554ec4e8f51aa578568afc230799fe1a19", size = 696397, upload-time = "2026-08-07T10:48:08.03Z" }, - { url = "https://files.pythonhosted.org/packages/2e/0f/1aed6223d4f9f9d1171a8596ff100ea4c3f7699fea7a4ba657c3e60daa6c/librt-0.15.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b845b8d48088fad0cadc84be4b8fda63203be7e9237b71015b3925443c1f35ab", size = 722542, upload-time = "2026-08-07T10:48:09.569Z" }, - { url = "https://files.pythonhosted.org/packages/c6/22/9e3a929aea456c97d69e6ef3884efea56d4807f97399471cc946baebd8af/librt-0.15.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b30e600e8f337b9bd7f39b86d9fdfedc73cc46e3d0f745931a23a234220bb7e2", size = 729709, upload-time = "2026-08-07T10:48:11.129Z" }, - { url = "https://files.pythonhosted.org/packages/e9/1b/c327ef6018e3a9ca0b8e7c5eddeeb331ba8f9b76c24e126d37d0f6d62faf/librt-0.15.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:64b0c8c35aa4c4ed79896359f3e0b285cbe4e610042106500da4811c322cc108", size = 752891, upload-time = "2026-08-07T10:48:12.558Z" }, - { url = "https://files.pythonhosted.org/packages/d7/d1/d5f1ea02c56930087009e39db9b70660a663e76c730b27b925d786718457/librt-0.15.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0da0d94cb802f32a0524653e7201f2cef72d5f700a5407678f5290483d4fcd08", size = 745301, upload-time = "2026-08-07T10:48:14.55Z" }, - { url = "https://files.pythonhosted.org/packages/d9/3c/5f7c585d15ebb2250c73e7c0ee4e9e47be72c65d520c07ddbcdc62037674/librt-0.15.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4a6369168d371207339b1e50d4532b06a7121586141f82599505a3f315751d47", size = 747921, upload-time = "2026-08-07T10:48:16.453Z" }, - { url = "https://files.pythonhosted.org/packages/7f/52/1443a446486eba966bcbca1696b472e4f210320ec42f490a47f48fbf0fdc/librt-0.15.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c434e072557ade9cbc642d052c89d031efe47d5c9614523619d0d74a02378e81", size = 727561, upload-time = "2026-08-07T10:48:18.089Z" }, - { url = "https://files.pythonhosted.org/packages/79/91/2270a9380f11725cf83ce1925a5e32dd1dde2be9bba597f25c10a38644e7/librt-0.15.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7eec6a42018bc1d45763b1c162d3d2bf7c3b9a1b0ed30d3e91dcba390efefcc", size = 774417, upload-time = "2026-08-07T10:48:19.611Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3b/f4b1548d4f5b99186737fe27aec238e9823e8d5d23bf4df007c030689dc5/librt-0.15.0-cp314-cp314t-win32.whl", hash = "sha256:6912fa5e635d74529ac7cdb1bdf6ca3af4453da8d1edbe0110ee1cb4ad407ebf", size = 104381, upload-time = "2026-08-07T10:48:21.048Z" }, - { url = "https://files.pythonhosted.org/packages/80/b6/134afad262def1de04c0843c376d02135f1168af43f22e09a52bd8394727/librt-0.15.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8e11699ed745931c395acd3621b07062e0f840efa6935aad87a64ed0995f0915", size = 127034, upload-time = "2026-08-07T10:48:22.561Z" }, - { url = "https://files.pythonhosted.org/packages/99/5f/1b6846b20572bd699c9e9ec321a5f781845bee477df2aa2a43b28bc40119/librt-0.15.0-cp314-cp314t-win_arm64.whl", hash = "sha256:5d2a91724463bfed4f573cd7a9fdc856d2e230d0c0e5a61416a93481dccd8605", size = 110827, upload-time = "2026-08-07T10:48:23.804Z" }, - { url = "https://files.pythonhosted.org/packages/c6/44/4de9f4ddadb009a55c7758eb5736d62534a7daaf27bd71bc50e64b606b06/librt-0.15.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:8443e38dcfcfdbcf5add5118c623efd788d65ac2e25756d6251a54a06a4d0aca", size = 149843, upload-time = "2026-08-07T10:48:25.148Z" }, - { url = "https://files.pythonhosted.org/packages/1f/eb/5d9ab71e30119c44094e0275f38b47dd327aea0f843a080396677029d508/librt-0.15.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:6d15a29033c57490cfe2069097c6fc4049e4e65ffbb749be7dc453b7c4c68965", size = 154510, upload-time = "2026-08-07T10:48:26.485Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9c/8505d1b8f5e8c19587bd03f7429993b3e9ce5c06819d856bfb11d919374c/librt-0.15.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d2c05c729b589e734c09578bf5964be48a911765484840d017bbc84f49d4c4ad", size = 497543, upload-time = "2026-08-07T10:48:28.045Z" }, - { url = "https://files.pythonhosted.org/packages/1d/9a/3a8390775cb095765aded027ac9c63e7c8ea74e731498607544c6505de0e/librt-0.15.0-cp315-cp315-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:fa60887537e1d0cd2d9982269d33a709bf54b195cd2b9364fc0a758022af5bd9", size = 480452, upload-time = "2026-08-07T10:48:29.531Z" }, - { url = "https://files.pythonhosted.org/packages/e7/40/258a4a7117ee915d66de5cd9b8ade65a440993161107ce3a686f1859955c/librt-0.15.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d8bc24219b24c0af375718942ab75e3544b2763085f40f965be4326734ae8328", size = 507768, upload-time = "2026-08-07T10:48:31.007Z" }, - { url = "https://files.pythonhosted.org/packages/6b/c6/2f4dd296c97a0b85b98894519b279408ec9dd602d4f692b1ea0e25dee670/librt-0.15.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86a21a7bd3fe3a419512ef424cc1c020f6771d0b29cfddff36d1635a855e63f0", size = 525122, upload-time = "2026-08-07T10:48:32.7Z" }, - { url = "https://files.pythonhosted.org/packages/49/dd/29eab42be13b2bf0ea8cb227135a45d44693e30a7e8b92871981ff56b82b/librt-0.15.0-cp315-cp315-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dbab647e88d90b3167b91efe7091e248653688ed4337e4f90907a722c7361bb9", size = 520371, upload-time = "2026-08-07T10:48:34.294Z" }, - { url = "https://files.pythonhosted.org/packages/91/ed/4bad71adeca8fe208b775c2a35417fa5a2584c8f4791daaf89a89450fea1/librt-0.15.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:d8edcf6f550e918dca779c069b9e156385c60b406f99fc7641f32c52f7193659", size = 537258, upload-time = "2026-08-07T10:48:35.88Z" }, - { url = "https://files.pythonhosted.org/packages/4c/63/59dba6143fdcc7240c54458b629f3250000a61b8945890fc9efd451b19c5/librt-0.15.0-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:8b62076030baa2d8b1501a46bf0e19c27a489aa90671c55665bff7887f7660b0", size = 527432, upload-time = "2026-08-07T10:48:37.466Z" }, - { url = "https://files.pythonhosted.org/packages/ec/21/21a24c6a2327d8362580efebe77286bf47b0f4062ec5ea41766e609d3c7d/librt-0.15.0-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:d00d20d1818e82a07a0ee0aa89a98b17ed7916b92441090b683719cb20a59b6d", size = 548108, upload-time = "2026-08-07T10:48:39.384Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6d/fc68c89a7971418b41f9a873623ff935cb864097544c6a2f8ce491c8ef5d/librt-0.15.0-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:4e6ee93fc3cf848dcbf0cce2eca73d8e7dcd0cc2b6df3a529d57750b30a4c55c", size = 529681, upload-time = "2026-08-07T10:48:41.392Z" }, - { url = "https://files.pythonhosted.org/packages/65/7e/c2d98766124400d722063a630b0fde38a9fc768705d37eecca15c47dc192/librt-0.15.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:32896a0af72508ea979e0acb4e4c04cbeeae04938167950d535c83c45597167d", size = 567736, upload-time = "2026-08-07T10:48:43.124Z" }, - { url = "https://files.pythonhosted.org/packages/55/6c/f8c34a95e3a515c6e1c192b89511e7253c89a7760c6b500d57ffdb8d2dc8/librt-0.15.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:ec3ba415afaf951f6951b1dd16d3c8e4f540065fc382d7e70b823a79567ca374", size = 81673, upload-time = "2026-08-07T10:48:44.645Z" }, - { url = "https://files.pythonhosted.org/packages/c9/9e/e23fa8e78679ec45728188650b39e8ff476c83b691c96f749217df3b1b7c/librt-0.15.0-cp315-cp315-win32.whl", hash = "sha256:d2813ba2503764f0450680c533d13df7cff9b49df1411062eded5f67db4195b9", size = 100081, upload-time = "2026-08-07T10:48:46.171Z" }, - { url = "https://files.pythonhosted.org/packages/e1/dc/3eb4c5e297343f0620a55532cd7c8d764d3001fa2159212dadf480464827/librt-0.15.0-cp315-cp315-win_amd64.whl", hash = "sha256:b87d67e33afaf265262f2a66db578284b88ee2e6fcd224579cb5c15518677ad8", size = 121228, upload-time = "2026-08-07T10:48:47.631Z" }, - { url = "https://files.pythonhosted.org/packages/97/70/43abce19f04e49762f8ec834c8fafee13cc40fd6b94a72a24e534febfcd0/librt-0.15.0-cp315-cp315-win_arm64.whl", hash = "sha256:713bd7df21170b982e729e46870f31d6b437bd1a9b4648cffb529bd3c2ec5c4b", size = 106487, upload-time = "2026-08-07T10:48:49.095Z" }, - { url = "https://files.pythonhosted.org/packages/de/15/83f2deddb9368b8951ec8c9477269b5b9b8bd9bbf15e57402d0f38817dca/librt-0.15.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:3de789c82752730f94782a5ee518baf9c05edf85733aeaf73bb6e518755cdf54", size = 159448, upload-time = "2026-08-07T10:48:50.649Z" }, - { url = "https://files.pythonhosted.org/packages/06/bf/043097353f9b3c73b583d07f6b8e552795463f4bfc8caf85e42eee50c26a/librt-0.15.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:e0b5deec9a8664eb722c797241970fd4aa1894d25fda36a1ddac0f7407606bd6", size = 161686, upload-time = "2026-08-07T10:48:52.174Z" }, - { url = "https://files.pythonhosted.org/packages/f4/2a/8ae77f9719d42ce71cd708560a3557b38ac3c17a0383e57f87084de45bbe/librt-0.15.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5563302a8359bc2295bb7084d1a8ed1519df96afb30eb2aa4e0bff7b54228988", size = 710668, upload-time = "2026-08-07T10:48:53.782Z" }, - { url = "https://files.pythonhosted.org/packages/61/34/c0436ea134deb9a0d6da80a396a2739a81cb31e0418f7227239e23140898/librt-0.15.0-cp315-cp315t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:22d6263b9d39d7bbb286fa791945646e3218f1be2d693e36fb630f1d0e59cd13", size = 679396, upload-time = "2026-08-07T10:48:55.645Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9f/001e0d99aa9250d5cd5715a9081291a20656083459f9019cda15255329e1/librt-0.15.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39ffd14646190c454f0d86e0d256b33f00a87a26ab410e619773b841d0e41416", size = 704313, upload-time = "2026-08-07T10:48:57.46Z" }, - { url = "https://files.pythonhosted.org/packages/2d/53/b34fa9d0ff00f136f4d58ebb4c411ff634baed1eb412bb602a2bc8dcafcb/librt-0.15.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c47318cd3a61401452de11282242937e3e057c4fd3dbaf601e269d0928a06c0a", size = 729847, upload-time = "2026-08-07T10:48:59.231Z" }, - { url = "https://files.pythonhosted.org/packages/86/ac/fa4d7a424665040e95baf480a6d523446057684b6758624c85338e8a23b2/librt-0.15.0-cp315-cp315t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a56a1d4f859a82ca5b99fc4b82c9b027b15e3c455c5cd99e7d0719f27bb20b6c", size = 742736, upload-time = "2026-08-07T10:49:01.151Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f1/e17a9bb5de6fb8c3186ed1a7d68d21618b027ac2d3633e03d3b6109c67ae/librt-0.15.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:077471b3182db4e17c36ae91555f36a4d2c00080b267f749bcad34a478a9a302", size = 763454, upload-time = "2026-08-07T10:49:03.039Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ec/ecd02cd30935b931b9cdbfed6ab5a099c51b280b4e7baa274da80978ed27/librt-0.15.0-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:411ca4d1b905b860ceba7570dd6717a71dedaddcc4b0f77ece710aa41ee11f8d", size = 743296, upload-time = "2026-08-07T10:49:04.941Z" }, - { url = "https://files.pythonhosted.org/packages/e6/b5/b3c2b8353ce820a4854f78d19321344242f89fa71c975b71132ba9bf242a/librt-0.15.0-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:1256589e0b0adb31751d685a68bce29d73407ddf4ef05d4188f49d5dcf9566d9", size = 756217, upload-time = "2026-08-07T10:49:06.825Z" }, - { url = "https://files.pythonhosted.org/packages/3c/52/6cc22542ba59146b05cca2a656f9ff8bb67e38e63d12c3b0cc183d837bf1/librt-0.15.0-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:f42b74a53e5f26a0ba0007411a7455b66c67ce4022a39cc1f56fc4efd65bcbab", size = 741934, upload-time = "2026-08-07T10:49:08.839Z" }, - { url = "https://files.pythonhosted.org/packages/40/32/a04b72b1aa86e3be23b2ecff8c1aad2dcc955bd3956d6d26e7e34267e57a/librt-0.15.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:291bf73caf78b9e88d6fae9bfd693207ff7d832e2fdbe2cf8e746bc13f5f892b", size = 783763, upload-time = "2026-08-07T10:49:10.661Z" }, - { url = "https://files.pythonhosted.org/packages/6c/f0/89eb11dffbe9279ff37144dec786927314502ae0b114f1449dc78c458aab/librt-0.15.0-cp315-cp315t-win32.whl", hash = "sha256:c16d15ee371643ab48dc8248a3e680ebbeca573a13af2c3dd0c985b142d77162", size = 104313, upload-time = "2026-08-07T10:49:12.305Z" }, - { url = "https://files.pythonhosted.org/packages/6d/4a/1f1978c200f563beda63c36adff2d65bbecb81e365e8e69e572f5f70fbc6/librt-0.15.0-cp315-cp315t-win_amd64.whl", hash = "sha256:dbd605739f228912dc49027cb764456b9757750bdc2b6b7773164db7096c6fd1", size = 126889, upload-time = "2026-08-07T10:49:13.881Z" }, - { url = "https://files.pythonhosted.org/packages/38/a6/800800bfed7b1fb10fc3f3d557785c3854e80d3f7a9800d784b176a1fc2d/librt-0.15.0-cp315-cp315t-win_arm64.whl", hash = "sha256:84d244b00604d17df3fc7736c327892d6bba66181254aa4087be807b6c342bdc", size = 110700, upload-time = "2026-08-07T10:49:15.499Z" }, -] - [[package]] name = "markdown-it-py" version = "3.0.0" @@ -1455,82 +1261,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, ] -[[package]] -name = "mypy" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ast-serialize" }, - { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, - { name = "mypy-extensions" }, - { name = "pathspec" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/82/6a/878cc1097d4035f82bd516658d0c528d2a9955bc7b363afcbd0b07fea11b/mypy-2.3.1.tar.gz", hash = "sha256:47c1b1207258513a9d93495f69c8be9de73916186f0e52703e8c461b7a623419", size = 3992554, upload-time = "2026-08-15T03:03:38.549Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/b9/de8f67e12d721cdcc8ba6cfc440b989a4ba4dfabe4402ae94dfdd8bb30a4/mypy-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:57a936373fc690c43a8cd7e7e12a35148e4ec5aa7698ad7fc0a9f918bdc5be41", size = 14015541, upload-time = "2026-08-15T03:01:53.104Z" }, - { url = "https://files.pythonhosted.org/packages/f1/8a/9e746ab012c67ed8ea3232a613716c306ee8c0b5682c80d8103b4f04568e/mypy-2.3.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d00d769056bde2f4e69c175071eba45cfb44fa1ed92bdfbfe64a93e0543b0cf0", size = 14248142, upload-time = "2026-08-15T03:02:43.201Z" }, - { url = "https://files.pythonhosted.org/packages/f7/5c/c99ff2d8d0e2c53393e32dfe22d9aa43a5d959d30db46c786dafd24527d3/mypy-2.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2166b29228835e1f88ff411e96639e6ca3c7fdde84b62ec211f70f86b4051167", size = 15193309, upload-time = "2026-08-15T03:01:28.714Z" }, - { url = "https://files.pythonhosted.org/packages/64/39/124638f745243faae1ff4b37d5426fe41c0f0454535edc82fe8102b56a3c/mypy-2.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:83d36c2924df7426333abe7faf4724a7e1aab0d9fd41625e81b4683034b80c13", size = 15498246, upload-time = "2026-08-15T03:02:46.29Z" }, - { url = "https://files.pythonhosted.org/packages/b2/83/31c0781e243836505c0fb5f4e865487d6df1023e4ad959f4ebd4b84a0226/mypy-2.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:f12fdb70459d0060dea40b29e52163a961b156106d68d57882a6a9f648983a53", size = 11155028, upload-time = "2026-08-15T03:01:39.08Z" }, - { url = "https://files.pythonhosted.org/packages/a0/ab/bc2eb0129e72d7d7d93d5e981a78084a9abefda7efa732a7e02f97d6e27d/mypy-2.3.1-cp310-cp310-win_arm64.whl", hash = "sha256:e099200a1b1b1223a4951f0a90cbff1b8c91b250ba599dab1f7217a628144d90", size = 10151438, upload-time = "2026-08-15T03:02:19.04Z" }, - { url = "https://files.pythonhosted.org/packages/a4/be/c624d4241484f37dc62839e177ab607a9b8b3e96f0866544ca99e8e41d51/mypy-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94f04929f1c44c35fb0061e912087edaf504acede963a4a7d00680bd089d8531", size = 13936739, upload-time = "2026-08-15T03:03:26.475Z" }, - { url = "https://files.pythonhosted.org/packages/53/84/e3cf72f90dce5960871c82551c8fba6da05fc1018f79be41c047bd126bdd/mypy-2.3.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f5d716048611e85ca9eefb2e1baa5d73ede389b5820ded260ea27c757d667af8", size = 14166460, upload-time = "2026-08-15T03:01:50.565Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/6b97d58aa0f79a5ab9b472db1f6d6df1b11a51d74d0c08ab3760d3a613ba/mypy-2.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b091a455111214cb5c9d54a57b9618e9a49f9fe2a42e4e1ac86e9d104ed96ce8", size = 15100476, upload-time = "2026-08-15T03:03:12.079Z" }, - { url = "https://files.pythonhosted.org/packages/da/f0/cbb4b7d2ae3ac635f6b4f2d9b04070b8a92edf50da599d3b39e5ed109001/mypy-2.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df12e20c9efd614738c71b390007ecd0181125afc4ccafca04d78a1d2eed2c01", size = 15347826, upload-time = "2026-08-15T03:03:02.856Z" }, - { url = "https://files.pythonhosted.org/packages/5f/10/91dcdc6f8d43fc08e6a06ab1f9732f3abaaf835ac1b2e67b9dff56910855/mypy-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:52eaf3a155f35cf80b40220288c861eb45f14a2340c1f6cbfbdb0feff32879d1", size = 11142615, upload-time = "2026-08-15T03:03:36.316Z" }, - { url = "https://files.pythonhosted.org/packages/3d/8a/28d54535bf4b9aa43b2d8918c2ef660378b9f66b23d78dcee052744ae622/mypy-2.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:9b4eacbee8a69836c06eff6d0dd4e134a07c2b047755b30c08625fe214f322c6", size = 10141145, upload-time = "2026-08-15T03:03:07.406Z" }, - { url = "https://files.pythonhosted.org/packages/85/da/d6effc4f808a842d91edc22535dc9e799d2ff6e91449168b7f47a0771f54/mypy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a32bbbb940af990d3be0b8af321c7b6815bb1b3b48142fe7459b9cc5f58959ff", size = 14047547, upload-time = "2026-08-15T03:02:57.707Z" }, - { url = "https://files.pythonhosted.org/packages/e4/e6/478229701dab76f26485fc8ff5d6f241f393da22447400bbc56f6946aebe/mypy-2.3.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff715e45b2231a8e85de1d163d1b42791e4d7aab8f5145f85fee1b710b735aff", size = 14216515, upload-time = "2026-08-15T03:01:26.496Z" }, - { url = "https://files.pythonhosted.org/packages/8d/fe/7c42327a3b21e84681f691982cbfe43f334a3685f3b683b72c376476c4fa/mypy-2.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:858fc57d3d91fa728e33e7ad71def60fc6272694607b306cd3292db53ae39080", size = 15307789, upload-time = "2026-08-15T03:03:31.62Z" }, - { url = "https://files.pythonhosted.org/packages/59/f4/7e597edbe01b5a56fa958ce541302dcaabfed979966f1dffedbea0ea0fc2/mypy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:851833db876e7b650f93719c74b7879a08e338979c96054fdfc3bfd90a486355", size = 15548831, upload-time = "2026-08-15T03:03:15.55Z" }, - { url = "https://files.pythonhosted.org/packages/a3/52/cb31e084bc0314a1e384bdd677a4b80e55af04ccac077545e2238b9d320a/mypy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:4c5095a327483591c94e0c8d3ef9e50d4ab1369b541eae007c1f23bc2a41f6bb", size = 11226359, upload-time = "2026-08-15T03:03:29.002Z" }, - { url = "https://files.pythonhosted.org/packages/7a/47/88fcf6217b43fa2da81a8c2611370af18141536a4f0294bbf98b457d456d/mypy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:bbfe022634a2a195406bd469e888d2eaf193b02ba7e607391cd7640374aaae3b", size = 10214707, upload-time = "2026-08-15T03:02:48.807Z" }, - { url = "https://files.pythonhosted.org/packages/de/cf/862010ee800ca9c2bd0c4c0dacf0f092e5411824a09b8f97ad4be8fe250e/mypy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:114dff494000f18bd10d5d95d84b8567b26da60279ecbe838131841df20e635d", size = 13964542, upload-time = "2026-08-15T03:02:21.43Z" }, - { url = "https://files.pythonhosted.org/packages/75/5a/3f3a2107b41e3e92e617e25daaee121413b91e9784bea733131ed4fecc5d/mypy-2.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8637731bb5eee3671eb2c3200827aa3564ed8a9309ecee4d1afe77e6d031bdb", size = 14168922, upload-time = "2026-08-15T03:03:00.351Z" }, - { url = "https://files.pythonhosted.org/packages/8b/41/04dc4fe7e63d7820fa4eff272e95157d30cbea921388f3ab3fe77794cd0b/mypy-2.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c80fbc405ed8020f5ff3802dc18cf060197bcdd3fbdd6a26ef2fd34dfdd5226", size = 15244791, upload-time = "2026-08-15T03:02:31.089Z" }, - { url = "https://files.pythonhosted.org/packages/96/fc/c3053b26b9054949285aa868cb6af8c10e7591541cacd79c5dcc06a1fcf9/mypy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:84081f538ce27375045c02e3d7f81bd11d853400621ae245d87ce7b6c420ec74", size = 15501627, upload-time = "2026-08-15T03:03:34.128Z" }, - { url = "https://files.pythonhosted.org/packages/70/4e/d77daab008bbc4e5001374d7928f4a260d28f0e6747af444fc4763f7a310/mypy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:e9144ac16fde007096f9563eb2041b4433c2d705c4218edeb79e7e9d01035ee6", size = 11243961, upload-time = "2026-08-15T03:02:11.952Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f8/7eb68c136e4abd30569fe31ef2bfcb7eceae9952cab80017c04cd09f5d0c/mypy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:77ad9529e67dca28e511f5cd5671436584ce91f6d3bac159a353158187b986ac", size = 10213219, upload-time = "2026-08-15T03:02:26.361Z" }, - { url = "https://files.pythonhosted.org/packages/be/c4/42a49d44aeff804edf1b19acce0b49e8bd1a9c57dee9605dd8d980aa43d7/mypy-2.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:192abaedf75da1bc0b1cef104927e70ec49c1ef0031cc4825c7ee10a438ed24d", size = 13986778, upload-time = "2026-08-15T03:01:33.69Z" }, - { url = "https://files.pythonhosted.org/packages/45/13/9331fd2dfed7194d66c5304072894a8be3e51e9deda6863c1eceaa35a43d/mypy-2.3.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf678dffd16efcda2c15cbd30e9ecc0081388e29ea23687a88e686ed92638dc3", size = 14188467, upload-time = "2026-08-15T03:02:40.554Z" }, - { url = "https://files.pythonhosted.org/packages/78/f7/f4a34edab45667c5465855dc585a20e87978ffa8aee711445b7239d120c6/mypy-2.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e036f06b41630f4c8a1d48f9ac6aa26acc65f8be089973f5519da643318f03f", size = 15225538, upload-time = "2026-08-15T03:03:09.761Z" }, - { url = "https://files.pythonhosted.org/packages/40/05/534b3590757bd05794f73e07f6666c2a77b8597ffed795c94ce570096aa0/mypy-2.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:71af9c8a894e862b58e92abb08e53b05a384a1e5e5d6dc7cda59126211a53d82", size = 15480805, upload-time = "2026-08-15T03:01:41.134Z" }, - { url = "https://files.pythonhosted.org/packages/55/da/bdfba852e2562f599624af5bb7d29e36b0b4f526f2b8bac85efe0dd1803d/mypy-2.3.1-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:3c80cd23d85368bdd9f37d5231dfd97d35bcbf5bf41af96ef3a9b078ad1957f9", size = 7761712, upload-time = "2026-08-15T03:02:36.008Z" }, - { url = "https://files.pythonhosted.org/packages/98/31/60fc64a74cdba4f2a5d642d32317993e479163e1ac7d91b695e5d15e2264/mypy-2.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:4956f34d145e145562a0a0bf367f642bbc85c04ec2baf47ae015947c3169a85d", size = 11423968, upload-time = "2026-08-15T03:02:06.931Z" }, - { url = "https://files.pythonhosted.org/packages/a9/23/eb5950b24cd26ba3b78f87707a275568d633c77dae8e61c9661be6055ca6/mypy-2.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:cfb12e360242d23d91f5e978d94f58ea66acf5804c4fb6f2f794a20d4cb1b595", size = 10399323, upload-time = "2026-08-15T03:02:33.671Z" }, - { url = "https://files.pythonhosted.org/packages/82/c7/f80f4e46c0b9a00eb5f78a79d49dda8bdf56a5230f7257fb33e76be04da7/mypy-2.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5f1c50bb05b64e2026b52867e8d21106f01313c744a2c4ecc34c90d12e8d6e2", size = 15121308, upload-time = "2026-08-15T03:01:46.053Z" }, - { url = "https://files.pythonhosted.org/packages/5d/74/9b04f17c7074cc5188f02fb63a2ca1d43fedf479e84fe3091c39061a1d7f/mypy-2.3.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:667196b352f4cf304ded4c10f90cfc179263a1acfb3cdcfa984bdfd340d498bc", size = 15536590, upload-time = "2026-08-15T03:01:35.941Z" }, - { url = "https://files.pythonhosted.org/packages/26/04/c837ef6208e567774e2ed1f863f8ba6ec4817b1b6dd426315e5d559b6ec9/mypy-2.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b9c53e395c12cad2c6d4b67d5da7c6057638a132d85c08b73646b18f802a0045", size = 16791074, upload-time = "2026-08-15T03:01:31.073Z" }, - { url = "https://files.pythonhosted.org/packages/37/68/48730230afa45192d5bd429a6a2ff24a6f8dedda90fdf2b221792b54518f/mypy-2.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:18162b128c3f9c703cd35f5537446900b0d21a2549aa7a95d21380d2ef643fb0", size = 17069183, upload-time = "2026-08-15T03:02:28.566Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ea/ca23fc9c20eeda09a15c9cbcf50015d0e73f409f6ead059e42aa69a608ff/mypy-2.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:30c0477d4aab7b7f39c8397dc877f2c96b9fe5588ec379f372c56eb63d599f63", size = 12154679, upload-time = "2026-08-15T03:02:04.809Z" }, - { url = "https://files.pythonhosted.org/packages/3b/67/8d982126034990869466f73b8db80dcb2234a7ac39b4dad093e047a79835/mypy-2.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:6941ab3619377bc3f32ca02876b07d27f216f5201604b664d3937ea0fdd23bb4", size = 10969159, upload-time = "2026-08-15T03:02:38.152Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f7/41e7f2d8117fbc7a7587286162ffe2f688984b69c46ed63cf5f2e4fc3bae/mypy-2.3.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:6f041a6de52c9217ca125e78ba0a335cb7fd98a1c0580978e49ab2b126f70b57", size = 13990694, upload-time = "2026-08-15T03:03:21.919Z" }, - { url = "https://files.pythonhosted.org/packages/06/85/8f665811a0c8f3bf6fa1d9acd665ec2d97a2bcc453ae68dcd92340941cd6/mypy-2.3.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5159ae60f5dbc3a498af5ba8365505808ac8031bc63f9e00304ad545d40bdd9b", size = 14203518, upload-time = "2026-08-15T03:01:48.455Z" }, - { url = "https://files.pythonhosted.org/packages/2d/82/91b866c8546b120bff83b73a439d90d2d63ef3aff113599e6b8e4d566848/mypy-2.3.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47a8a7a0a7f6f6e63995c0ac36fa0c07b127413fdc81f0439b7f3dccafd33561", size = 15220224, upload-time = "2026-08-15T03:01:23.577Z" }, - { url = "https://files.pythonhosted.org/packages/c8/78/c226c99208ee40de7c768369fa533f933afa003dfdc606ff021450724e91/mypy-2.3.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:2329c0501293d4e1f33bc15d04d6304d65a1cdda967ee93a05c1e681a3923133", size = 15501512, upload-time = "2026-08-15T03:02:09.453Z" }, - { url = "https://files.pythonhosted.org/packages/a9/e7/7cfb3f106c393979f4cc37ad6c0586044d50401e3c35b0c003e4f3ba6bc9/mypy-2.3.1-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:bb26deed807bdb0457cf3e3f1cd7c4a1cf9d66864eaf1b4a61e06805d4c6b1f9", size = 7761913, upload-time = "2026-08-15T03:01:55.65Z" }, - { url = "https://files.pythonhosted.org/packages/99/3c/52affefa273b97939a1f474ae4a349c8718635c15b941112dfab4291b0c1/mypy-2.3.1-cp315-cp315-win_amd64.whl", hash = "sha256:375d7013876a8233b2d05be185bfa09f689696cd999ce8b1cfe6acac5c80e8a3", size = 11422533, upload-time = "2026-08-15T03:03:24.101Z" }, - { url = "https://files.pythonhosted.org/packages/2a/b7/75643e70c72a5b346d8a9b1543c967ea8824df2ee3fb7ccba652c272b7bb/mypy-2.3.1-cp315-cp315-win_arm64.whl", hash = "sha256:586b3612214cceabb3c0f588c97e7d1e535393f06a60e912e994f6b3ace97523", size = 10397931, upload-time = "2026-08-15T03:02:55.265Z" }, - { url = "https://files.pythonhosted.org/packages/10/ce/53be21f2d4adfcd26f63f1184a13ed797015ab463853f117e2e11e4d726f/mypy-2.3.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:ef0c6335cda9d807f8193d8ff6204a72bc909fa9882aacbca14f43cdb7188306", size = 15118669, upload-time = "2026-08-15T03:02:51.479Z" }, - { url = "https://files.pythonhosted.org/packages/62/43/20de757cd42989d291a17fad607742c4c74e875ce5cea00e5a5225020ac1/mypy-2.3.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e598c8c66401d26b150872154a286e6d484cf2789c3bb28a7556806298423021", size = 15545627, upload-time = "2026-08-15T03:03:05.132Z" }, - { url = "https://files.pythonhosted.org/packages/7e/fc/092bdf77ad280eaf501422f0f3b966012b528076cc13e41a774861c907d1/mypy-2.3.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eda22fd4efa9dcd39331d1dede9b5b8b8a7fd69af07592e778433da98610d29e", size = 16764157, upload-time = "2026-08-15T03:02:23.958Z" }, - { url = "https://files.pythonhosted.org/packages/94/5c/c94c4d62d909b07f552d0d9356d7acc943825558e602a64822ffa2231536/mypy-2.3.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:2a0ba2e57847849fb0d1fcdabb32786d223095ed8bc121dfe322bcdb3d9c46bc", size = 17073258, upload-time = "2026-08-15T03:02:14.573Z" }, - { url = "https://files.pythonhosted.org/packages/c0/f7/511a88b89e478053c02d22039bb8f3ce4183efe8fd7a4f0a5910a8bb0a32/mypy-2.3.1-cp315-cp315t-win_amd64.whl", hash = "sha256:3f7e865dd51f235f60a2dbcd8728a1c095f5ca28f095d48a725b84cd935735c4", size = 12135505, upload-time = "2026-08-15T03:02:16.714Z" }, - { url = "https://files.pythonhosted.org/packages/71/bf/02573b56964ecb0f7c644f915f53c325ae15c3faec521c5adf11599a32df/mypy-2.3.1-cp315-cp315t-win_arm64.whl", hash = "sha256:8ad80807dc3ab8ea978b1b2b6e4a657194ace1d4ef03e0e731aff1abd517da29", size = 10962647, upload-time = "2026-08-15T03:01:43.712Z" }, - { url = "https://files.pythonhosted.org/packages/8e/41/9675c7a1e78edecfba0b79e587a52594c56e189368261dc7b3a7fffb9527/mypy-2.3.1-py3-none-any.whl", hash = "sha256:6ed5c7e3419083268e5c9258bd1c1ef91af44a9e89374dbcaf37b775716e72eb", size = 2754338, upload-time = "2026-08-15T03:02:53.4Z" }, -] - -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - [[package]] name = "numpy" version = "2.2.6" @@ -1746,7 +1476,6 @@ dev = [ { name = "botocore" }, { name = "griffe" }, { name = "inline-snapshot" }, - { name = "mypy" }, { name = "pandas-stubs" }, { name = "pillow" }, { name = "pytest" }, @@ -1755,6 +1484,7 @@ dev = [ { name = "rich" }, { name = "ruff" }, { name = "trio" }, + { name = "ty" }, { name = "types-requests" }, ] provider-browser = [ @@ -1805,7 +1535,6 @@ dev = [ { name = "botocore", specifier = "==1.43.106" }, { name = "griffe", specifier = ">=1" }, { name = "inline-snapshot", specifier = ">=0.28.0" }, - { name = "mypy", specifier = "==2.3.1" }, { name = "pandas-stubs", specifier = ">=1.1.0.11" }, { name = "pillow", specifier = "==12.3.0" }, { name = "pytest", specifier = ">=9.0.3" }, @@ -1814,6 +1543,7 @@ dev = [ { name = "rich", specifier = ">=13.7.1" }, { name = "ruff" }, { name = "trio", specifier = ">=0.22.2" }, + { name = "ty", specifier = "==0.0.87" }, { name = "types-requests", specifier = ">=2.33.0.20261006" }, ] provider-browser = [{ name = "playwright", specifier = "==1.63.0" }] @@ -2706,6 +2436,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" }, ] +[[package]] +name = "ty" +version = "0.0.87" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/17/15/8a1e8008a4580c3c7bbf2a2e1a6e0001abbd265728426ffe7fc3eab29e98/ty-0.0.87.tar.gz", hash = "sha256:0f844e1fe0725a69753d22b46cb3dce653f3331ae8e332e46b0f22349a244093", size = 7941034, upload-time = "2026-10-13T23:07:08.993Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/31/6462292e264fc1fcd61bf3179d197e4e7cc21fe95f25660e6b59b6494af3/ty-0.0.87-py3-none-linux_armv6l.whl", hash = "sha256:1b78781402464a152da80b37d4af503912c0f8b882134cdfcdc2dbbd3f914024", size = 14134045, upload-time = "2026-10-13T23:06:18.791Z" }, + { url = "https://files.pythonhosted.org/packages/67/12/6c93cf5f2ce2a00176e8d580d06fc6deb79c13def13c64d833b25860c34f/ty-0.0.87-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7e4a164821ca74733bcaf1a5cca05e0fb7b2bd7b846385b3aa2a042a60d0a0bc", size = 13705845, upload-time = "2026-10-13T23:06:22.031Z" }, + { url = "https://files.pythonhosted.org/packages/f1/03/7cc79acc2a01b3e7146ae8c3df2445c7fe4930e54c3d8b9c052bfa27f389/ty-0.0.87-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d38ebf4da3fb234676236b38e03d24014aa3522af8533c6f0f5eccd4a9de147e", size = 12795984, upload-time = "2026-10-13T23:06:24.969Z" }, + { url = "https://files.pythonhosted.org/packages/8a/be/db90201ef1ce9a79e5cefbf7d8faa80eadc2b4f05a7a32ac126b1d33c815/ty-0.0.87-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6ed0a498db9fa8ffb421014698fbca6fa32699d9544156aeeda763b8d8984d0", size = 13659572, upload-time = "2026-10-13T23:06:27.974Z" }, + { url = "https://files.pythonhosted.org/packages/e7/6e/8e59624cbb81358fd6560fe7a2d0994b6531052dd9729e972b8a362325ca/ty-0.0.87-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b9a3538293a2aef66fb618cf70ef60f5dca23479dc008ad4ff4b861cff043e78", size = 13860982, upload-time = "2026-10-13T23:06:31.115Z" }, + { url = "https://files.pythonhosted.org/packages/61/ba/6f444935dc40ba16805aedefcd0ee942a682de1fb85c794620233320cbab/ty-0.0.87-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73d540684ec438b5087cbb218898b6030395055698e9132fccc52267e5820522", size = 14834270, upload-time = "2026-10-13T23:06:34.406Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ef/6339f9af05479215a5f351c287e86b2acacd941c918dbe3f702dced32c97/ty-0.0.87-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61c3fded55b32db1a6944f12079c859c7d03da17cd666858ae8acca5a6c15af7", size = 15218871, upload-time = "2026-10-13T23:06:37.224Z" }, + { url = "https://files.pythonhosted.org/packages/9c/98/fa7b9a8dce2248436b13728ad6462f47293c01141ec4afc0184073e6d93f/ty-0.0.87-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75bf154f9f4ea24c3fa2b8d610aee4bfb2ee7ba8f78d9cd763a896a829a87a2a", size = 15134752, upload-time = "2026-10-13T23:06:40.231Z" }, + { url = "https://files.pythonhosted.org/packages/3a/62/dc4d7135c5ea1bf6f5429509113e1c8092ff4e55399f527c508edaba20bb/ty-0.0.87-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8caa3316ea81e794fcd98d1e4d3aaa5fae84790154d88c3e85ac3bd01c537bd", size = 14510734, upload-time = "2026-10-13T23:06:43.029Z" }, + { url = "https://files.pythonhosted.org/packages/35/76/2fd26f136ae967095f222ce75ad58d2c8472da355fc4a6d24662d8c98123/ty-0.0.87-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:930b045a2965f3332d5dbad8ed47076aaeb5c6ead6addf3d4d4e10bc37929901", size = 14681985, upload-time = "2026-10-13T23:06:45.867Z" }, + { url = "https://files.pythonhosted.org/packages/fe/b9/38ea15b4c4c5167f9c93ab5062fe438acff9e7851af615c7580722da2aaa/ty-0.0.87-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:547226807687a240bb2e3c52ef37cdf25b2b33f200dcc659bfa3aac61028b259", size = 13592754, upload-time = "2026-10-13T23:06:48.469Z" }, + { url = "https://files.pythonhosted.org/packages/fb/ce/ca367cee9e4ea5cee7b0b60c37f1d091789e4c784192003ba7695dc18f53/ty-0.0.87-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2791e65f320cd8af1a7b46eed458b09710efb455add9138d4a973352b171ca30", size = 13881344, upload-time = "2026-10-13T23:06:51.55Z" }, + { url = "https://files.pythonhosted.org/packages/02/3b/042a2dd75d83f7bd94afe2c1fd25dbbbbe01ec56c27a4108804068f8e0d2/ty-0.0.87-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4a1eb91eb6de896a3f93847e171d1cf63e3490518bfa3cc69b0e635e9d16d7d0", size = 14259114, upload-time = "2026-10-13T23:06:54.476Z" }, + { url = "https://files.pythonhosted.org/packages/21/99/500885b4ee1f825bde8b3c45ef42dff869d4f30328f34bac90c75065953e/ty-0.0.87-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ed384e2d5e72b14664344e676d091f7ec693ad580d69cd204e01732542e4bf7", size = 14573555, upload-time = "2026-10-13T23:06:57.159Z" }, + { url = "https://files.pythonhosted.org/packages/79/39/09f9274119899ed4e15630a544735c31b32f6bbaeea4c40a788cecf8df3d/ty-0.0.87-py3-none-win32.whl", hash = "sha256:12c85c47d62d3b03c3ef00e1e74a31788aac5de3102d86b687d928d889cfbe83", size = 13137336, upload-time = "2026-10-13T23:06:59.816Z" }, + { url = "https://files.pythonhosted.org/packages/4e/6e/ecfc716c98bb1eeac9d8743221403c5e7f2f0ed69858af881a0e5b775739/ty-0.0.87-py3-none-win_amd64.whl", hash = "sha256:767219b8fedd2f48875c1ea3557f39734642073a2e039c6ab67ce5a50b65ddf0", size = 13660330, upload-time = "2026-10-13T23:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/94/89/aa0eb234360cb6c8efc6ac45694000dfe3c3e590a30e87f2f9631190d339/ty-0.0.87-py3-none-win_arm64.whl", hash = "sha256:db4aa3a464c43d155ac8a3387a76173183ce4c141a8de1b6cb956e6a5a5e7d52", size = 13217514, upload-time = "2026-10-13T23:07:06.177Z" }, +] + [[package]] name = "types-pytz" version = "2025.2.0.20251108"