diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ccc7f01..7abc8f1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' @@ -17,9 +19,9 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/asktable-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rye run: | @@ -36,15 +38,15 @@ jobs: run: ./scripts/lint build: - if: github.repository == 'stainless-sdks/asktable-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') timeout-minutes: 10 name: build permissions: contents: read id-token: write - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/asktable-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rye run: | @@ -61,12 +63,18 @@ jobs: run: rye build - name: Get GitHub OIDC Token + if: |- + github.repository == 'stainless-sdks/asktable-python' && + !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball + if: |- + github.repository == 'stainless-sdks/asktable-python' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} @@ -79,7 +87,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/asktable-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rye run: | diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 188841d6..4d689123 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install Rye run: | diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 1800bc5b..5fdb3b54 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'DataMini/asktable-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check release environment run: | diff --git a/.gitignore b/.gitignore index 87797408..3824f4c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .prism.log -.vscode +.stdy.log _dev __pycache__ diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f425d970..8d050425 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "5.5.0" + ".": "5.6.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index b3408abe..3892a600 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 107 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-420512609e3f9f33f8a5b2d0086d4d3152b78935f1dc689cf4c5adf245241ba8.yml -openapi_spec_hash: a0055c3c329900b7a66dc27f4bea86cb +configured_endpoints: 42 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini/asktable-37a9799265b47e1bb64d698549bcbee32659894542e78c62c3c8362b95cb00d8.yml +openapi_spec_hash: e88e8fa9566058b51176e43c3e605add config_hash: acdf4142177ed1932c2d82372693f811 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..5b010307 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.importFormat": "relative", +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 320a4033..8b4ddf23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,97 @@ # Changelog +## 5.6.0 (2026-06-07) + +Full Changelog: [v5.5.0...v5.6.0](https://github.com/DataMini/asktable-python/compare/v5.5.0...v5.6.0) + +### Features + +* **api:** api update ([7e1cfe3](https://github.com/DataMini/asktable-python/commit/7e1cfe3a9b6a4aadd5839f39455e25c2db6f2d17)) +* **api:** api update ([26ab859](https://github.com/DataMini/asktable-python/commit/26ab8592b1428b91553816b17457d42eea15adc7)) +* **api:** api update ([fe539bc](https://github.com/DataMini/asktable-python/commit/fe539bc74c59fdce2b7a40c5e26bd9244f386130)) +* **api:** api update ([e6afbb2](https://github.com/DataMini/asktable-python/commit/e6afbb2f257f7a43aaba082f3feca5495bf12d59)) +* **api:** api update ([929d9ba](https://github.com/DataMini/asktable-python/commit/929d9ba34cd8acaa8edf37082c4ec17a655997bc)) +* **api:** api update ([f973c1d](https://github.com/DataMini/asktable-python/commit/f973c1d881d52a59acbbb3297b228aa45f511a45)) +* **api:** api update ([cbf5c8b](https://github.com/DataMini/asktable-python/commit/cbf5c8baec50e7040b3661ebac4109d3e7a0c974)) +* **api:** api update ([5a4459d](https://github.com/DataMini/asktable-python/commit/5a4459db1b4bf749a120fd8365d6755b98a6849c)) +* **api:** api update ([2ac5002](https://github.com/DataMini/asktable-python/commit/2ac50023a3cf7a9ce750e6f74a5b2b0b1ca58f05)) +* **api:** api update ([2ad193d](https://github.com/DataMini/asktable-python/commit/2ad193d7d26f51f8e2080b2c7018865eec6346b5)) +* **api:** api update ([8f315ae](https://github.com/DataMini/asktable-python/commit/8f315ae44dd5f63bb6ee94eeb8a05db4be061185)) +* **api:** api update ([e5b4763](https://github.com/DataMini/asktable-python/commit/e5b4763c4be305b5e8eb00bfc4ccce4ac21b0859)) +* **api:** api update ([d1ef26f](https://github.com/DataMini/asktable-python/commit/d1ef26f8728272e1be6c1f82012ec15bf3fda39f)) +* **api:** api update ([6d705b0](https://github.com/DataMini/asktable-python/commit/6d705b07546e449d03e5e0f70f859a49c8db14ec)) +* **api:** api update ([783819b](https://github.com/DataMini/asktable-python/commit/783819b560f7f0b9b26a3177acbd1174de6cd259)) +* **api:** api update ([5981a58](https://github.com/DataMini/asktable-python/commit/5981a58a11a85d7a1d8341a563f51137719c7850)) +* **api:** api update ([871a8c7](https://github.com/DataMini/asktable-python/commit/871a8c7c65874d07e0329f8490df11f2e8daa0fe)) +* **api:** api update ([dc5a071](https://github.com/DataMini/asktable-python/commit/dc5a07103bfc42c3f4e5acba1a61cb06b1c2a714)) +* **api:** api update ([1784353](https://github.com/DataMini/asktable-python/commit/1784353bb71b8c263b54e1e3ad95d7f25f1c5bea)) +* **api:** api update ([9260b13](https://github.com/DataMini/asktable-python/commit/9260b13ed921f7ea0f9615999375e92327e6ae98)) +* **api:** api update ([2acb60f](https://github.com/DataMini/asktable-python/commit/2acb60fc6c0bbb12713548b388f3289e85efb2fb)) +* **api:** api update ([9a4f19a](https://github.com/DataMini/asktable-python/commit/9a4f19a8ae3655969fd42c89ddce37e344fecd34)) +* **api:** api update ([b4fe8f6](https://github.com/DataMini/asktable-python/commit/b4fe8f6225f6190443c96098dcd368be97ec7e44)) +* **api:** api update ([4271a76](https://github.com/DataMini/asktable-python/commit/4271a76c22284d1b2a1bdd2a0a658afba2bcc181)) +* **api:** api update ([1176bed](https://github.com/DataMini/asktable-python/commit/1176beda5149dba11a79fc7e02988f74f6e60aae)) +* **api:** api update ([02a8fff](https://github.com/DataMini/asktable-python/commit/02a8fff21477f2c32241a09141bb4095c0060d30)) +* **api:** api update ([8add1bf](https://github.com/DataMini/asktable-python/commit/8add1bf8ed03a6e674c63e405a0cbf3f3d06b104)) +* **api:** api update ([9ec8ffd](https://github.com/DataMini/asktable-python/commit/9ec8ffda5236139d9241cd8507b7798b9312b3dd)) +* **api:** api update ([5dbbf4f](https://github.com/DataMini/asktable-python/commit/5dbbf4fd77e617963eeaca8fd57054ddb3ebad05)) +* **api:** api update ([343d8d1](https://github.com/DataMini/asktable-python/commit/343d8d1db4e22208b3d3b335f2d51de166a64a22)) +* **api:** api update ([c5b1360](https://github.com/DataMini/asktable-python/commit/c5b136000d8771c1b8a9a8b3843316d12c7ba6d9)) +* **api:** api update ([9492d82](https://github.com/DataMini/asktable-python/commit/9492d823c21d636d68e654e485ef99ab07344b47)) +* **api:** api update ([692c5e4](https://github.com/DataMini/asktable-python/commit/692c5e4a06ed72d630cae83806a89eb36316e647)) +* **api:** api update ([a62c00a](https://github.com/DataMini/asktable-python/commit/a62c00ae12cbc0efdbcb4bdf02480ddbb36d693a)) +* **api:** api update ([94adaea](https://github.com/DataMini/asktable-python/commit/94adaeae5c0a3ab51b8d4f9ef9acba27d87efc06)) +* **api:** api update ([d79fd22](https://github.com/DataMini/asktable-python/commit/d79fd224c090d22b32cc02776c5fd32ea56d2a7b)) +* **api:** api update ([d3cbda0](https://github.com/DataMini/asktable-python/commit/d3cbda00e41261e559ba2111b843b1b10f9fb772)) +* **api:** api update ([8e94324](https://github.com/DataMini/asktable-python/commit/8e94324216695bc96c20ed8b066a342d35b1f377)) +* **api:** api update ([689b9c0](https://github.com/DataMini/asktable-python/commit/689b9c0c7863e30ea3a614607c1aac22f5745b52)) +* **api:** api update ([8e2933a](https://github.com/DataMini/asktable-python/commit/8e2933a2a07175e5b2a817f9243df5952b19a9fa)) +* **api:** api update ([8fa327a](https://github.com/DataMini/asktable-python/commit/8fa327a7bb92dc4b4aeb81ff356989c13712166d)) +* **api:** api update ([7a17247](https://github.com/DataMini/asktable-python/commit/7a17247ed3d0cb95ec279c1627b51dfb2ce48572)) +* **api:** api update ([fd21534](https://github.com/DataMini/asktable-python/commit/fd2153419e2ba1424b40398fef454d01db6d4a79)) +* **client:** support file upload requests ([e9bac63](https://github.com/DataMini/asktable-python/commit/e9bac63f9b86123f21df0343e44bd9423e053bbe)) +* improve future compat with pydantic v3 ([7d6836d](https://github.com/DataMini/asktable-python/commit/7d6836dc486cd6287e806f18177b2c4afb1be2e5)) +* support setting headers via env ([c2ea4c0](https://github.com/DataMini/asktable-python/commit/c2ea4c0d7c59b5cfff82de1ce519874a24ec2168)) +* **types:** replace List[str] with SequenceNotStr in params ([be4a6d6](https://github.com/DataMini/asktable-python/commit/be4a6d685ff133354c4b242992de4a80f475c2d4)) + + +### Bug Fixes + +* avoid newer type syntax ([2bc84ae](https://github.com/DataMini/asktable-python/commit/2bc84ae95415f7377dcbf554faf6d057605f5c74)) +* **parsing:** ignore empty metadata ([8c48f1b](https://github.com/DataMini/asktable-python/commit/8c48f1b05dbebb99a432ab9fd7b57f8aed109d60)) +* **parsing:** parse extra field types ([40c9351](https://github.com/DataMini/asktable-python/commit/40c9351059a44df1f640f5791a126e175ebadad6)) + + +### Chores + +* **internal:** add Sequence related utils ([d34ae74](https://github.com/DataMini/asktable-python/commit/d34ae74d7dd281b8b1bc806aec5965a042550d88)) +* **internal:** change ci workflow machines ([1781814](https://github.com/DataMini/asktable-python/commit/17818149ddfaa3397db71e1a6a2500b997576a97)) +* **internal:** codegen related update ([99a17dd](https://github.com/DataMini/asktable-python/commit/99a17dd8134758616e8aeb31c796ea2e562f8d4c)) +* **internal:** codegen related update ([4ae6dcc](https://github.com/DataMini/asktable-python/commit/4ae6dccb04f43f2e9eeaa9e369425d9bbae3540e)) +* **internal:** codegen related update ([a19202a](https://github.com/DataMini/asktable-python/commit/a19202adce026c1c6066bb696db169d850c0ebae)) +* **internal:** codegen related update ([4d4bc3f](https://github.com/DataMini/asktable-python/commit/4d4bc3f5b62d34ed3eb3ae14328ccd334396dfbf)) +* **internal:** codegen related update ([58cb854](https://github.com/DataMini/asktable-python/commit/58cb854f16cb8009d5a5825a77f2e4c6e05e2d40)) +* **internal:** codegen related update ([72943ae](https://github.com/DataMini/asktable-python/commit/72943aea0fee5fd0724c466e017a3cb2c14a3882)) +* **internal:** codegen related update ([66a354b](https://github.com/DataMini/asktable-python/commit/66a354b2db9b6b0eecbd2c732e26e45f81082a04)) +* **internal:** codegen related update ([12c3e97](https://github.com/DataMini/asktable-python/commit/12c3e97327ac9b5709c11794e8d1697b041ff5b0)) +* **internal:** codegen related update ([d60ba62](https://github.com/DataMini/asktable-python/commit/d60ba627627abf7310d0464d679d332ef9ba6e65)) +* **internal:** codegen related update ([f1cea4d](https://github.com/DataMini/asktable-python/commit/f1cea4d395932285e627b2695d2b95b3cc880296)) +* **internal:** codegen related update ([4277012](https://github.com/DataMini/asktable-python/commit/42770122e37df0e03d7f5643da5aef8ab61e8a55)) +* **internal:** codegen related update ([0c6162b](https://github.com/DataMini/asktable-python/commit/0c6162b65b8b1034dd6f9c65aff9020f41fd6af9)) +* **internal:** codegen related update ([86b895b](https://github.com/DataMini/asktable-python/commit/86b895bc21b209f651ab062637ca506a34e96992)) +* **internal:** fix ruff target version ([47ae330](https://github.com/DataMini/asktable-python/commit/47ae33089939da844b9fc6f96ea1d7a56d57887e)) +* **internal:** move mypy configurations to `pyproject.toml` file ([3a81ab1](https://github.com/DataMini/asktable-python/commit/3a81ab10fc9090dd6e0c850ebf4d2bc5dd0774aa)) +* **internal:** update comment in script ([595c402](https://github.com/DataMini/asktable-python/commit/595c4022caf668b57ad4dab50ec2e8a7dc3227af)) +* **internal:** update pydantic dependency ([7768ab5](https://github.com/DataMini/asktable-python/commit/7768ab57521d3e09e550013c14b188e6aeb62fd1)) +* **internal:** update pyright exclude list ([5bf3c78](https://github.com/DataMini/asktable-python/commit/5bf3c78a9d79882f1c2e7e4245187cbb1813229d)) +* **project:** add settings file for vscode ([1641a3d](https://github.com/DataMini/asktable-python/commit/1641a3d8c4a5647a81b6292b3fd8805ab3132bb8)) +* **tests:** bump steady to v0.19.7 ([7887929](https://github.com/DataMini/asktable-python/commit/7887929ff15541ebb8120765c55f84a6c3bd39d3)) +* **tests:** bump steady to v0.20.2 ([c48a104](https://github.com/DataMini/asktable-python/commit/c48a104834af9699b011fa5891cb4c1941a5bb27)) +* **tests:** simplify `get_platform` test ([f8251b5](https://github.com/DataMini/asktable-python/commit/f8251b5a76926a6603865967d8e94071a72f5d26)) +* **types:** change optional parameter type from NotGiven to Omit ([e2ab3d3](https://github.com/DataMini/asktable-python/commit/e2ab3d3508972ea2ac5df4ab1824036070eaf732)) +* update @stainless-api/prism-cli to v5.15.0 ([5d3abad](https://github.com/DataMini/asktable-python/commit/5d3abad79640464784e731af282d02600606db98)) +* update github action ([653ff06](https://github.com/DataMini/asktable-python/commit/653ff06315c440c09e931828916b8ff38a41d6bd)) + ## 5.5.0 (2025-07-19) Full Changelog: [v5.4.0...v5.5.0](https://github.com/DataMini/asktable-python/compare/v5.4.0...v5.5.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 58c9d1e9..0c4ed922 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -85,11 +85,10 @@ $ pip install ./path-to-wheel-file.whl ## Running tests -Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. +Most tests require you to [set up a mock server](https://github.com/dgellow/steady) against the OpenAPI spec to run the tests. ```sh -# you will need npm installed -$ npx prism mock path/to/your/openapi.yml +$ ./scripts/mock ``` ```sh diff --git a/LICENSE b/LICENSE index fed4ca4d..881cc1fc 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Asktable + Copyright 2026 Asktable Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index cab856b6..aa944739 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![PyPI version](https://img.shields.io/pypi/v/asktable.svg?label=pypi%20(stable))](https://pypi.org/project/asktable/) -The Asktable Python library provides convenient access to the Asktable REST API from any Python 3.8+ +The Asktable Python library provides convenient access to the Asktable REST API from any Python 3.9+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). @@ -83,6 +83,7 @@ pip install asktable[aiohttp] Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python +import os import asyncio from asktable import DefaultAioHttpClient from asktable import AsyncAsktable @@ -90,7 +91,7 @@ from asktable import AsyncAsktable async def main() -> None: async with AsyncAsktable( - api_key="My API Key", + api_key=os.environ.get("ASKTABLE_API_KEY"), # This is the default and can be omitted http_client=DefaultAioHttpClient(), ) as client: datasource = await client.datasources.create( @@ -190,24 +191,6 @@ response = client.sys.projects.api_keys.create_token( print(response.chat_role) ``` -## File uploads - -Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. - -```python -from pathlib import Path -from asktable import Asktable - -client = Asktable() - -client.datasources.add_file( - datasource_id="datasource_id", - file=Path("/path/to/file"), -) -``` - -The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically. - ## Handling errors When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `asktable.APIConnectionError` is raised. @@ -469,7 +452,7 @@ print(asktable.__version__) ## Requirements -Python 3.8 or higher. +Python 3.9 or higher. ## Contributing diff --git a/api.md b/api.md index 4d02c1ed..defe9aa8 100644 --- a/api.md +++ b/api.md @@ -6,22 +6,18 @@ from asktable.types import Policy # Sys -Types: - -```python -from asktable.types import SyUpdateConfigResponse -``` - -Methods: - -- client.sys.update_config(\*\*params) -> SyUpdateConfigResponse - ## Projects Types: ```python -from asktable.types.sys import APIKey, ModelGroup, Project, ProjectModelGroupsResponse +from asktable.types.sys import ( + APIKey, + Project, + ProjectExportResponse, + ProjectImportResponse, + ProjectModelGroupsResponse, +) ``` Methods: @@ -31,8 +27,8 @@ Methods: - client.sys.projects.update(project_id, \*\*params) -> Project - client.sys.projects.list(\*\*params) -> SyncPage[Project] - client.sys.projects.delete(project_id) -> object -- client.sys.projects.export(project_id) -> object -- client.sys.projects.import\_(\*\*params) -> object +- client.sys.projects.export(project_id) -> ProjectExportResponse +- client.sys.projects.import\_(\*\*params) -> ProjectImportResponse - client.sys.projects.model_groups() -> ProjectModelGroupsResponse ### APIKeys @@ -40,7 +36,11 @@ Methods: Types: ```python -from asktable.types.sys.projects import APIKeyCreateResponse, APIKeyListResponse +from asktable.types.sys.projects import ( + APIKeyCreateResponse, + APIKeyListResponse, + APIKeyCreateTokenResponse, +) ``` Methods: @@ -48,82 +48,16 @@ Methods: - client.sys.projects.api_keys.create(project_id, \*\*params) -> APIKeyCreateResponse - client.sys.projects.api_keys.list(project_id) -> APIKeyListResponse - client.sys.projects.api_keys.delete(key_id, \*, project_id) -> None -- client.sys.projects.api_keys.create_token(project_id, \*\*params) -> object - -# Securetunnels - -Types: - -```python -from asktable.types import SecureTunnel, SecuretunnelListLinksResponse -``` - -Methods: - -- client.securetunnels.create(\*\*params) -> SecureTunnel -- client.securetunnels.retrieve(securetunnel_id) -> SecureTunnel -- client.securetunnels.update(securetunnel_id, \*\*params) -> SecureTunnel -- client.securetunnels.list(\*\*params) -> SyncPage[SecureTunnel] -- client.securetunnels.delete(securetunnel_id) -> None -- client.securetunnels.list_links(securetunnel_id, \*\*params) -> SyncPage[SecuretunnelListLinksResponse] +- client.sys.projects.api_keys.create_token(project_id, \*\*params) -> APIKeyCreateTokenResponse # Roles Types: ```python -from asktable.types import Role, RoleGetPolicesResponse +from asktable.types import Role ``` -Methods: - -- client.roles.create(\*\*params) -> Role -- client.roles.retrieve(role_id) -> Role -- client.roles.update(role_id, \*\*params) -> Role -- client.roles.list(\*\*params) -> SyncPage[Role] -- client.roles.delete(role_id) -> object -- client.roles.get_polices(role_id) -> RoleGetPolicesResponse -- client.roles.get_variables(role_id, \*\*params) -> object - -# Policies - -Methods: - -- client.policies.create(\*\*params) -> Policy -- client.policies.retrieve(policy_id) -> Policy -- client.policies.update(policy_id, \*\*params) -> Policy -- client.policies.list(\*\*params) -> SyncPage[Policy] -- client.policies.delete(policy_id) -> None - -# Chats - -Types: - -```python -from asktable.types import AIMessage, Chat, ToolMessage, UserMessage, ChatRetrieveResponse -``` - -Methods: - -- client.chats.create(\*\*params) -> Chat -- client.chats.retrieve(chat_id) -> ChatRetrieveResponse -- client.chats.list(\*\*params) -> SyncPage[Chat] -- client.chats.delete(chat_id) -> None - -## Messages - -Types: - -```python -from asktable.types.chats import MessageCreateResponse, MessageRetrieveResponse, MessageListResponse -``` - -Methods: - -- client.chats.messages.create(chat_id, \*\*params) -> MessageCreateResponse -- client.chats.messages.retrieve(message_id, \*, chat_id) -> MessageRetrieveResponse -- client.chats.messages.list(chat_id, \*\*params) -> SyncPage[MessageListResponse] - # Datasources Types: @@ -161,9 +95,15 @@ Methods: ## UploadParams +Types: + +```python +from asktable.types.datasources import UploadParamCreateResponse +``` + Methods: -- client.datasources.upload_params.create(\*\*params) -> object +- client.datasources.upload_params.create(\*\*params) -> UploadParamCreateResponse ## Indexes @@ -173,130 +113,24 @@ Methods: - client.datasources.indexes.list(ds_id, \*\*params) -> SyncPage[Index] - client.datasources.indexes.delete(index_id, \*, ds_id) -> object -# Bots - -Types: - -```python -from asktable.types import Chatbot -``` - -Methods: - -- client.bots.create(\*\*params) -> Chatbot -- client.bots.retrieve(bot_id) -> Chatbot -- client.bots.update(bot_id, \*\*params) -> Chatbot -- client.bots.list(\*\*params) -> SyncPage[Chatbot] -- client.bots.delete(bot_id) -> object -- client.bots.invite(bot_id, \*\*params) -> object - # Auth Types: ```python -from asktable.types import AuthMeResponse +from asktable.types import AuthCreateTokenResponse, AuthMeResponse ``` Methods: -- client.auth.create_token(\*\*params) -> object +- client.auth.create_token(\*\*params) -> AuthCreateTokenResponse - client.auth.me() -> AuthMeResponse -# Answers - -Types: - -```python -from asktable.types import AnswerResponse -``` - -Methods: - -- client.answers.create(\*\*params) -> AnswerResponse -- client.answers.list(\*\*params) -> SyncPage[AnswerResponse] - -# Sqls - -Types: - -```python -from asktable.types import QueryResponse -``` - -Methods: - -- client.sqls.create(\*\*params) -> QueryResponse -- client.sqls.list(\*\*params) -> SyncPage[QueryResponse] - -# Caches - -Methods: - -- client.caches.delete(cache_id) -> None - # Integration -Types: - -```python -from asktable.types import FileAskResponse -``` - -Methods: - -- client.integration.create_excel_ds(\*\*params) -> Datasource -- client.integration.excel_csv_ask(\*\*params) -> FileAskResponse - -# BusinessGlossary - -Types: - -```python -from asktable.types import Entry, EntryWithDefinition, BusinessGlossaryCreateResponse -``` - Methods: -- client.business_glossary.create(\*\*params) -> BusinessGlossaryCreateResponse -- client.business_glossary.retrieve(entry_id) -> EntryWithDefinition -- client.business_glossary.update(entry_id, \*\*params) -> Entry -- client.business_glossary.list(\*\*params) -> SyncPage[EntryWithDefinition] -- client.business_glossary.delete(entry_id) -> object - -# Preferences - -Types: - -```python -from asktable.types import ( - PreferenceCreateResponse, - PreferenceRetrieveResponse, - PreferenceUpdateResponse, -) -``` - -Methods: - -- client.preferences.create(\*\*params) -> PreferenceCreateResponse -- client.preferences.retrieve() -> PreferenceRetrieveResponse -- client.preferences.update(\*\*params) -> PreferenceUpdateResponse -- client.preferences.delete() -> object - -# Trainings - -Types: - -```python -from asktable.types import TrainingCreateResponse, TrainingUpdateResponse, TrainingListResponse -``` - -Methods: - -- client.trainings.create(\*\*params) -> TrainingCreateResponse -- client.trainings.update(id, \*\*params) -> TrainingUpdateResponse -- client.trainings.list(\*\*params) -> SyncPage[TrainingListResponse] -- client.trainings.delete(id, \*\*params) -> object +- client.integration.excel_csv_ask(\*\*params) -> object # Project @@ -314,15 +148,9 @@ Methods: # Scores -Types: - -```python -from asktable.types import ScoreCreateResponse -``` - Methods: -- client.scores.create(\*\*params) -> ScoreCreateResponse +- client.scores.create(\*\*params) -> object # Files @@ -369,65 +197,3 @@ Methods: - client.user.projects.retrieve_model_groups() -> ProjectRetrieveModelGroupsResponse - client.user.projects.retrieve_my_project() -> Project - client.user.projects.update_my_project(\*\*params) -> Project - -# ATS - -Types: - -```python -from asktable.types import ( - ATSCreateResponse, - ATSRetrieveResponse, - ATSUpdateResponse, - ATSListResponse, -) -``` - -Methods: - -- client.ats.create(\*\*params) -> ATSCreateResponse -- client.ats.retrieve(ats_id) -> ATSRetrieveResponse -- client.ats.update(ats_id, \*\*params) -> ATSUpdateResponse -- client.ats.list(\*\*params) -> SyncPage[ATSListResponse] -- client.ats.delete(ats_id, \*\*params) -> object - -## TestCase - -Types: - -```python -from asktable.types.ats import ( - TestCaseCreateResponse, - TestCaseRetrieveResponse, - TestCaseUpdateResponse, - TestCaseListResponse, -) -``` - -Methods: - -- client.ats.test_case.create(ats_id, \*\*params) -> TestCaseCreateResponse -- client.ats.test_case.retrieve(atc_id, \*, ats_id) -> TestCaseRetrieveResponse -- client.ats.test_case.update(atc_id, \*, ats_id, \*\*params) -> TestCaseUpdateResponse -- client.ats.test_case.list(ats_id, \*\*params) -> SyncPage[TestCaseListResponse] -- client.ats.test_case.delete(atc_id, \*, ats_id) -> object - -## Task - -Types: - -```python -from asktable.types.ats import ( - TaskRetrieveResponse, - TaskListResponse, - TaskGetCaseTasksResponse, - TaskRunResponse, -) -``` - -Methods: - -- client.ats.task.retrieve(ats_task_id, \*, ats_id) -> TaskRetrieveResponse -- client.ats.task.list(ats_id, \*\*params) -> SyncPage[TaskListResponse] -- client.ats.task.get_case_tasks(ats_task_id, \*, ats_id, \*\*params) -> TaskGetCaseTasksResponse -- client.ats.task.run(ats_id, \*\*params) -> TaskRunResponse diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index b0156385..00000000 --- a/mypy.ini +++ /dev/null @@ -1,50 +0,0 @@ -[mypy] -pretty = True -show_error_codes = True - -# 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. -exclude = ^(src/asktable/_files\.py|_dev/.*\.py|tests/.*)$ - -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 -[mypy.overrides] -module = "black.files.*" -ignore_errors = true -ignore_missing_imports = true diff --git a/pyproject.toml b/pyproject.toml index 371a4680..436fc005 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,30 +1,32 @@ [project] name = "asktable" -version = "5.5.0" +version = "5.6.0" description = "The official Python library for the Asktable API" dynamic = ["readme"] license = "Apache-2.0" authors = [ { name = "Asktable", email = "hi@datamini.ai" }, ] + dependencies = [ - "httpx>=0.23.0, <1", - "pydantic>=1.9.0, <3", - "typing-extensions>=4.10, <5", - "anyio>=3.5.0, <5", - "distro>=1.7.0, <2", - "sniffio", + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.14, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", ] -requires-python = ">= 3.8" + +requires-python = ">= 3.9" classifiers = [ "Typing :: Typed", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", @@ -39,14 +41,14 @@ Homepage = "https://github.com/DataMini/asktable-python" Repository = "https://github.com/DataMini/asktable-python" [project.optional-dependencies] -aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] [tool.rye] managed = true # version pins are in requirements-dev.lock dev-dependencies = [ "pyright==1.1.399", - "mypy", + "mypy==1.17", "respx", "pytest", "pytest-asyncio", @@ -56,7 +58,6 @@ dev-dependencies = [ "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", - "nest_asyncio==1.6.0", "pytest-xdist>=3.6.1", ] @@ -68,7 +69,7 @@ format = { chain = [ # run formatting again to fix any inconsistencies when imports are stripped "format:ruff", ]} -"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" +"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" "format:ruff" = "ruff format" "lint" = { chain = [ @@ -142,12 +143,13 @@ filterwarnings = [ # 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.8" +pythonVersion = "3.9" exclude = [ "_dev", ".venv", ".nox", + ".git", ] reportImplicitOverride = true @@ -156,10 +158,62 @@ reportOverlappingOverload = false reportImportCycles = false reportPrivateUsage = false +[tool.mypy] +pretty = true +show_error_codes = true + +# 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. +exclude = ["src/asktable/_files.py", "_dev/.*.py", "tests/.*"] + +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.ruff] line-length = 120 output-format = "grouped" -target-version = "py37" +target-version = "py38" [tool.ruff.format] docstring-code-format = true @@ -172,6 +226,8 @@ select = [ "B", # remove unused imports "F401", + # check for missing future annotations + "FA102", # bare except statements "E722", # unused arguments @@ -194,6 +250,8 @@ unfixable = [ "T203", ] +extend-safe-fixes = ["FA102"] + [tool.ruff.lint.flake8-tidy-imports.banned-api] "functools.lru_cache".msg = "This function does not retain type information for the wrapped function's arguments; The `lru_cache` function from `_utils` should be used instead" diff --git a/requirements-dev.lock b/requirements-dev.lock index 9701ab71..55d68a97 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -12,40 +12,45 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.8 +aiohttp==3.13.3 # via asktable # via httpx-aiohttp -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.12.1 # via asktable # via httpx -argcomplete==3.1.2 +argcomplete==3.6.3 # via nox async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 + # via nox +backports-asyncio-runner==1.2.0 + # via pytest-asyncio +certifi==2026.1.4 # via httpcore # via httpx -colorlog==6.7.0 +colorlog==6.10.1 + # via nox +dependency-groups==1.3.1 # via nox -dirty-equals==0.6.0 -distlib==0.3.7 +dirty-equals==0.11 +distlib==0.4.0 # via virtualenv -distro==1.8.0 +distro==1.9.0 # via asktable -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio # via pytest -execnet==2.1.1 +execnet==2.1.2 # via pytest-xdist -filelock==3.12.4 +filelock==3.19.1 # via virtualenv -frozenlist==1.6.2 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -56,80 +61,89 @@ httpx==0.28.1 # via asktable # via httpx-aiohttp # via respx -httpx-aiohttp==0.1.8 +httpx-aiohttp==0.1.12 # via asktable -idna==3.4 +humanize==4.13.0 + # via nox +idna==3.11 # via anyio # via httpx # via yarl -importlib-metadata==7.0.0 -iniconfig==2.0.0 +importlib-metadata==8.7.1 +iniconfig==2.1.0 # via pytest markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -multidict==6.4.4 +multidict==6.7.0 # via aiohttp # via yarl -mypy==1.14.1 -mypy-extensions==1.0.0 +mypy==1.17.0 +mypy-extensions==1.1.0 # via mypy -nest-asyncio==1.6.0 -nodeenv==1.8.0 +nodeenv==1.10.0 # via pyright -nox==2023.4.22 -packaging==23.2 +nox==2025.11.12 +packaging==25.0 + # via dependency-groups # via nox # via pytest -platformdirs==3.11.0 +pathspec==1.0.3 + # via mypy +platformdirs==4.4.0 # via virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via pytest -propcache==0.3.1 +propcache==0.4.1 # via aiohttp # via yarl -pydantic==2.10.3 +pydantic==2.12.5 # via asktable -pydantic-core==2.27.1 +pydantic-core==2.41.5 # via pydantic -pygments==2.18.0 +pygments==2.19.2 + # via pytest # via rich pyright==1.1.399 -pytest==8.3.3 +pytest==8.4.2 # via pytest-asyncio # via pytest-xdist -pytest-asyncio==0.24.0 -pytest-xdist==3.7.0 -python-dateutil==2.8.2 +pytest-asyncio==1.2.0 +pytest-xdist==3.8.0 +python-dateutil==2.9.0.post0 # via time-machine -pytz==2023.3.post1 - # via dirty-equals respx==0.22.0 -rich==13.7.1 -ruff==0.9.4 -setuptools==68.2.2 - # via nodeenv -six==1.16.0 +rich==14.2.0 +ruff==0.14.13 +six==1.17.0 # via python-dateutil -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via asktable -time-machine==2.9.0 -tomli==2.0.2 +time-machine==2.19.0 +tomli==2.4.0 + # via dependency-groups # via mypy + # via nox # via pytest -typing-extensions==4.12.2 +typing-extensions==4.15.0 + # via aiosignal # via anyio # via asktable + # via exceptiongroup # via multidict # via mypy # via pydantic # via pydantic-core # via pyright -virtualenv==20.24.5 + # via pytest-asyncio + # via typing-inspection + # via virtualenv +typing-inspection==0.4.2 + # via pydantic +virtualenv==20.36.1 # via nox -yarl==1.20.0 +yarl==1.22.0 # via aiohttp -zipp==3.17.0 +zipp==3.23.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index ac6e943f..7a238212 100644 --- a/requirements.lock +++ b/requirements.lock @@ -12,28 +12,28 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.8 +aiohttp==3.13.3 # via asktable # via httpx-aiohttp -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.12.1 # via asktable # via httpx async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 +certifi==2026.1.4 # via httpcore # via httpx -distro==1.8.0 +distro==1.9.0 # via asktable -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio -frozenlist==1.6.2 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -43,30 +43,34 @@ httpcore==1.0.9 httpx==0.28.1 # via asktable # via httpx-aiohttp -httpx-aiohttp==0.1.8 +httpx-aiohttp==0.1.12 # via asktable -idna==3.4 +idna==3.11 # via anyio # via httpx # via yarl -multidict==6.4.4 +multidict==6.7.0 # via aiohttp # via yarl -propcache==0.3.1 +propcache==0.4.1 # via aiohttp # via yarl -pydantic==2.10.3 +pydantic==2.12.5 # via asktable -pydantic-core==2.27.1 +pydantic-core==2.41.5 # via pydantic -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via asktable -typing-extensions==4.12.2 +typing-extensions==4.15.0 + # via aiosignal # via anyio # via asktable + # via exceptiongroup # via multidict # via pydantic # via pydantic-core -yarl==1.20.0 + # via typing-inspection +typing-inspection==0.4.2 + # via pydantic +yarl==1.22.0 # via aiohttp diff --git a/scripts/bootstrap b/scripts/bootstrap index e84fe62c..fe8451e4 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,10 +4,18 @@ set -e cd "$(dirname "$0")/.." -if ! command -v rye >/dev/null 2>&1 && [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { - echo "==> Installing Homebrew dependencies…" - brew bundle + echo -n "==> Install Homebrew dependencies? (y/N): " + read -r response + case "$response" in + [yY][eE][sS]|[yY]) + brew bundle + ;; + *) + ;; + esac + echo } fi diff --git a/scripts/lint b/scripts/lint index c49721d9..6d495229 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,8 +4,13 @@ set -e cd "$(dirname "$0")/.." -echo "==> Running lints" -rye run lint +if [ "$1" = "--fix" ]; then + echo "==> Running lints with --fix" + rye run fix:ruff +else + echo "==> Running lints" + rye run lint +fi echo "==> Making sure it imports" rye run python -c 'import asktable' diff --git a/scripts/mock b/scripts/mock index d2814ae6..9c7c4399 100755 --- a/scripts/mock +++ b/scripts/mock @@ -19,23 +19,34 @@ fi echo "==> Starting mock server with URL ${URL}" -# Run prism mock on the given spec +# Run steady mock on the given spec if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stdy/cli@0.22.1 -- steady --version - # Wait for server to come online + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + + # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + attempts=0 + while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + if ! kill -0 $! 2>/dev/null; then + echo + cat .stdy.log + exit 1 + fi + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Steady server to start" + cat .stdy.log + exit 1 + fi echo -n "." sleep 0.1 done - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - echo else - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 2b878456..0159035c 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,8 @@ GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 +function steady_is_running() { + curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 } kill_server_on_port() { @@ -25,7 +25,7 @@ function is_overriding_api_base_url() { [ -n "$TEST_API_BASE_URL" ] } -if ! is_overriding_api_base_url && ! prism_is_running ; then +if ! is_overriding_api_base_url && ! steady_is_running ; then # When we exit this script, make sure to kill the background mock server process trap 'kill_server_on_port 4010' EXIT @@ -36,19 +36,19 @@ fi if is_overriding_api_base_url ; then echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" +elif ! steady_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady server" echo -e "running against your OpenAPI spec." echo echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" + echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}" echo fi diff --git a/src/asktable/__init__.py b/src/asktable/__init__.py index 03765db6..38566e5b 100644 --- a/src/asktable/__init__.py +++ b/src/asktable/__init__.py @@ -3,7 +3,7 @@ import typing as _t from . import types -from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given from ._utils import file_from_path from ._client import ( Client, @@ -48,7 +48,9 @@ "ProxiesTypes", "NotGiven", "NOT_GIVEN", + "not_given", "Omit", + "omit", "AsktableError", "APIError", "APIStatusError", diff --git a/src/asktable/_base_client.py b/src/asktable/_base_client.py index 4678a3ee..133146bf 100644 --- a/src/asktable/_base_client.py +++ b/src/asktable/_base_client.py @@ -9,6 +9,7 @@ import inspect import logging import platform +import warnings import email.utils from types import TracebackType from random import random @@ -42,7 +43,6 @@ from ._qs import Querystring from ._files import to_httpx_files, async_to_httpx_files from ._types import ( - NOT_GIVEN, Body, Omit, Query, @@ -52,14 +52,17 @@ ResponseT, AnyMapping, PostParser, + BinaryTypes, RequestFiles, HttpxSendArgs, RequestOptions, + AsyncBinaryTypes, HttpxRequestFiles, ModelBuilderProtocol, + not_given, ) from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping -from ._compat import PYDANTIC_V2, model_copy, model_dump +from ._compat import PYDANTIC_V1, model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type from ._response import ( APIResponse, @@ -83,6 +86,7 @@ APIConnectionError, APIResponseValidationError, ) +from ._utils._json import openapi_dumps log: logging.Logger = logging.getLogger(__name__) @@ -145,9 +149,9 @@ def __init__( def __init__( self, *, - url: URL | NotGiven = NOT_GIVEN, - json: Body | NotGiven = NOT_GIVEN, - params: Query | NotGiven = NOT_GIVEN, + url: URL | NotGiven = not_given, + json: Body | NotGiven = not_given, + params: Query | NotGiven = not_given, ) -> None: self.url = url self.json = json @@ -232,7 +236,7 @@ def _set_private_attributes( model: Type[_T], options: FinalRequestOptions, ) -> None: - if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: self.__pydantic_private__ = {} self._model = model @@ -320,7 +324,7 @@ def _set_private_attributes( client: AsyncAPIClient, options: FinalRequestOptions, ) -> None: - if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: self.__pydantic_private__ = {} self._model = model @@ -477,8 +481,19 @@ def _build_request( retries_taken: int = 0, ) -> httpx.Request: if log.isEnabledFor(logging.DEBUG): - log.debug("Request options: %s", model_dump(options, exclude_unset=True)) - + log.debug( + "Request options: %s", + model_dump( + options, + exclude_unset=True, + # Pydantic v1 can't dump every type we support in content, so we exclude it for now. + exclude={ + "content", + } + if PYDANTIC_V1 + else {}, + ), + ) kwargs: dict[str, Any] = {} json_data = options.json_data @@ -525,6 +540,10 @@ def _build_request( files = cast(HttpxRequestFiles, ForceMultipartDict()) prepared_url = self._prepare_url(options.url) + # preserve hard-coded query params from the url + if params and prepared_url.query: + params = {**dict(prepared_url.params.items()), **params} + prepared_url = prepared_url.copy_with(raw_path=prepared_url.raw_path.split(b"?", 1)[0]) if "_" in prepared_url.host: # work around https://github.com/encode/httpx/discussions/2880 kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} @@ -532,7 +551,18 @@ def _build_request( is_body_allowed = options.method.lower() != "get" if is_body_allowed: - kwargs["json"] = json_data if is_given(json_data) else None + if options.content is not None and json_data is not None: + raise TypeError("Passing both `content` and `json_data` is not supported") + if options.content is not None and files is not None: + raise TypeError("Passing both `content` and `files` is not supported") + if options.content is not None: + kwargs["content"] = options.content + elif isinstance(json_data, bytes): + kwargs["content"] = json_data + elif not files: + # Don't set content when JSON is sent as multipart/form-data, + # since httpx's content param overrides other body arguments + kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None kwargs["files"] = files else: headers.pop("Content-Type", None) @@ -592,7 +622,7 @@ def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalReques # we internally support defining a temporary header to override the # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` # see _response.py for implementation details - override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, NOT_GIVEN) + override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) if is_given(override_cast_to): options.headers = headers return cast(Type[ResponseT], override_cast_to) @@ -822,7 +852,7 @@ def __init__( version: str, base_url: str | URL, max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, @@ -1191,6 +1221,7 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: Literal[False] = False, @@ -1203,6 +1234,7 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: Literal[True], @@ -1216,6 +1248,7 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: bool, @@ -1228,13 +1261,25 @@ def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, files: RequestFiles | None = None, stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, files=to_httpx_files(files), **options + method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options ) return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) @@ -1244,9 +1289,24 @@ def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options + ) return self.request(cast_to, opts) def put( @@ -1255,11 +1315,23 @@ def put( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, files=to_httpx_files(files), **options + method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options ) return self.request(cast_to, opts) @@ -1269,9 +1341,19 @@ def delete( *, cast_to: Type[ResponseT], body: Body | None = None, + content: BinaryTypes | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) return self.request(cast_to, opts) def get_api_list( @@ -1353,7 +1435,7 @@ def __init__( base_url: str | URL, _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, @@ -1711,6 +1793,7 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: Literal[False] = False, @@ -1723,6 +1806,7 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: Literal[True], @@ -1736,6 +1820,7 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: bool, @@ -1748,13 +1833,25 @@ async def post( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, stream: bool = False, stream_cls: type[_AsyncStreamT] | None = None, ) -> ResponseT | _AsyncStreamT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options + method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) @@ -1764,9 +1861,29 @@ async def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct( + method="patch", + url=path, + json_data=body, + content=content, + files=await async_to_httpx_files(files), + **options, + ) return await self.request(cast_to, opts) async def put( @@ -1775,11 +1892,23 @@ async def put( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if files is not None and content is not None: + raise TypeError("Passing both `files` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options + method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts) @@ -1789,9 +1918,19 @@ async def delete( *, cast_to: Type[ResponseT], body: Body | None = None, + content: AsyncBinaryTypes | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options) + if body is not None and content is not None: + raise TypeError("Passing both `body` and `content` is not supported") + if isinstance(body, bytes): + warnings.warn( + "Passing raw bytes as `body` is deprecated and will be removed in a future version. " + "Please pass raw bytes via the `content` parameter instead.", + DeprecationWarning, + stacklevel=2, + ) + opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) return await self.request(cast_to, opts) def get_api_list( @@ -1815,8 +1954,8 @@ def make_request_options( extra_query: Query | None = None, extra_body: Body | None = None, idempotency_key: str | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - post_parser: PostParser | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + post_parser: PostParser | NotGiven = not_given, ) -> RequestOptions: """Create a dict of type RequestOptions without keys of NotGiven values.""" options: RequestOptions = {} diff --git a/src/asktable/_client.py b/src/asktable/_client.py index 5c06a135..27da7210 100644 --- a/src/asktable/_client.py +++ b/src/asktable/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, Union, Mapping +from typing import TYPE_CHECKING, Any, Mapping from typing_extensions import Self, override import httpx @@ -11,35 +11,21 @@ from . import _exceptions from ._qs import Querystring from ._types import ( - NOT_GIVEN, Omit, Timeout, NotGiven, Transport, ProxiesTypes, RequestOptions, + not_given, ) -from ._utils import is_given, get_async_library -from ._version import __version__ -from .resources import ( - auth, - bots, - sqls, - files, - roles, - caches, - polish, - scores, - answers, - project, - policies, - trainings, - dataframes, - integration, - preferences, - securetunnels, - business_glossary, +from ._utils import ( + is_given, + is_mapping_t, + get_async_library, ) +from ._compat import cached_property +from ._version import __version__ from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import AsktableError, APIStatusError from ._base_client import ( @@ -47,11 +33,19 @@ SyncAPIClient, AsyncAPIClient, ) -from .resources.ats import ats -from .resources.sys import sys -from .resources.user import user -from .resources.chats import chats -from .resources.datasources import datasources + +if TYPE_CHECKING: + from .resources import sys, auth, user, files, polish, scores, project, dataframes, datasources, integration + from .resources.auth import AuthResource, AsyncAuthResource + from .resources.files import FilesResource, AsyncFilesResource + from .resources.polish import PolishResource, AsyncPolishResource + from .resources.scores import ScoresResource, AsyncScoresResource + from .resources.project import ProjectResource, AsyncProjectResource + from .resources.sys.sys import SysResource, AsyncSysResource + from .resources.user.user import UserResource, AsyncUserResource + from .resources.dataframes import DataframesResource, AsyncDataframesResource + from .resources.integration import IntegrationResource, AsyncIntegrationResource + from .resources.datasources.datasources import DatasourcesResource, AsyncDatasourcesResource __all__ = [ "Timeout", @@ -66,31 +60,6 @@ class Asktable(SyncAPIClient): - sys: sys.SysResource - securetunnels: securetunnels.SecuretunnelsResource - roles: roles.RolesResource - policies: policies.PoliciesResource - chats: chats.ChatsResource - datasources: datasources.DatasourcesResource - bots: bots.BotsResource - auth: auth.AuthResource - answers: answers.AnswersResource - sqls: sqls.SqlsResource - caches: caches.CachesResource - integration: integration.IntegrationResource - business_glossary: business_glossary.BusinessGlossaryResource - preferences: preferences.PreferencesResource - trainings: trainings.TrainingsResource - project: project.ProjectResource - scores: scores.ScoresResource - files: files.FilesResource - dataframes: dataframes.DataframesResource - polish: polish.PolishResource - user: user.UserResource - ats: ats.ATSResource - with_raw_response: AsktableWithRawResponse - with_streaming_response: AsktableWithStreamedResponse - # client options api_key: str @@ -99,7 +68,7 @@ def __init__( *, api_key: str | None = None, base_url: str | httpx.URL | None = None, - timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -134,6 +103,15 @@ def __init__( if base_url is None: base_url = f"https://api.asktable.com" + custom_headers_env = os.environ.get("ASKTABLE_CUSTOM_HEADERS") + if custom_headers_env is not None: + parsed: dict[str, str] = {} + for line in custom_headers_env.split("\n"): + colon = line.find(":") + if colon >= 0: + parsed[line[:colon].strip()] = line[colon + 1 :].strip() + default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} + super().__init__( version=__version__, base_url=base_url, @@ -145,30 +123,80 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.sys = sys.SysResource(self) - self.securetunnels = securetunnels.SecuretunnelsResource(self) - self.roles = roles.RolesResource(self) - self.policies = policies.PoliciesResource(self) - self.chats = chats.ChatsResource(self) - self.datasources = datasources.DatasourcesResource(self) - self.bots = bots.BotsResource(self) - self.auth = auth.AuthResource(self) - self.answers = answers.AnswersResource(self) - self.sqls = sqls.SqlsResource(self) - self.caches = caches.CachesResource(self) - self.integration = integration.IntegrationResource(self) - self.business_glossary = business_glossary.BusinessGlossaryResource(self) - self.preferences = preferences.PreferencesResource(self) - self.trainings = trainings.TrainingsResource(self) - self.project = project.ProjectResource(self) - self.scores = scores.ScoresResource(self) - self.files = files.FilesResource(self) - self.dataframes = dataframes.DataframesResource(self) - self.polish = polish.PolishResource(self) - self.user = user.UserResource(self) - self.ats = ats.ATSResource(self) - self.with_raw_response = AsktableWithRawResponse(self) - self.with_streaming_response = AsktableWithStreamedResponse(self) + @cached_property + def sys(self) -> SysResource: + from .resources.sys import SysResource + + return SysResource(self) + + @cached_property + def datasources(self) -> DatasourcesResource: + """数据源管理""" + from .resources.datasources import DatasourcesResource + + return DatasourcesResource(self) + + @cached_property + def auth(self) -> AuthResource: + """AskTable 系统认证管理""" + from .resources.auth import AuthResource + + return AuthResource(self) + + @cached_property + def integration(self) -> IntegrationResource: + """与第三方平台集成""" + from .resources.integration import IntegrationResource + + return IntegrationResource(self) + + @cached_property + def project(self) -> ProjectResource: + """我的项目""" + from .resources.project import ProjectResource + + return ProjectResource(self) + + @cached_property + def scores(self) -> ScoresResource: + """评分""" + from .resources.scores import ScoresResource + + return ScoresResource(self) + + @cached_property + def files(self) -> FilesResource: + """数据源管理""" + from .resources.files import FilesResource + + return FilesResource(self) + + @cached_property + def dataframes(self) -> DataframesResource: + from .resources.dataframes import DataframesResource + + return DataframesResource(self) + + @cached_property + def polish(self) -> PolishResource: + """润色""" + from .resources.polish import PolishResource + + return PolishResource(self) + + @cached_property + def user(self) -> UserResource: + from .resources.user import UserResource + + return UserResource(self) + + @cached_property + def with_raw_response(self) -> AsktableWithRawResponse: + return AsktableWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsktableWithStreamedResponse: + return AsktableWithStreamedResponse(self) @property @override @@ -195,9 +223,9 @@ def copy( *, api_key: str | None = None, base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, - max_retries: int | NotGiven = NOT_GIVEN, + max_retries: int | NotGiven = not_given, default_headers: Mapping[str, str] | None = None, set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -276,31 +304,6 @@ def _make_status_error( class AsyncAsktable(AsyncAPIClient): - sys: sys.AsyncSysResource - securetunnels: securetunnels.AsyncSecuretunnelsResource - roles: roles.AsyncRolesResource - policies: policies.AsyncPoliciesResource - chats: chats.AsyncChatsResource - datasources: datasources.AsyncDatasourcesResource - bots: bots.AsyncBotsResource - auth: auth.AsyncAuthResource - answers: answers.AsyncAnswersResource - sqls: sqls.AsyncSqlsResource - caches: caches.AsyncCachesResource - integration: integration.AsyncIntegrationResource - business_glossary: business_glossary.AsyncBusinessGlossaryResource - preferences: preferences.AsyncPreferencesResource - trainings: trainings.AsyncTrainingsResource - project: project.AsyncProjectResource - scores: scores.AsyncScoresResource - files: files.AsyncFilesResource - dataframes: dataframes.AsyncDataframesResource - polish: polish.AsyncPolishResource - user: user.AsyncUserResource - ats: ats.AsyncATSResource - with_raw_response: AsyncAsktableWithRawResponse - with_streaming_response: AsyncAsktableWithStreamedResponse - # client options api_key: str @@ -309,7 +312,7 @@ def __init__( *, api_key: str | None = None, base_url: str | httpx.URL | None = None, - timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -344,6 +347,15 @@ def __init__( if base_url is None: base_url = f"https://api.asktable.com" + custom_headers_env = os.environ.get("ASKTABLE_CUSTOM_HEADERS") + if custom_headers_env is not None: + parsed: dict[str, str] = {} + for line in custom_headers_env.split("\n"): + colon = line.find(":") + if colon >= 0: + parsed[line[:colon].strip()] = line[colon + 1 :].strip() + default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} + super().__init__( version=__version__, base_url=base_url, @@ -355,30 +367,80 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.sys = sys.AsyncSysResource(self) - self.securetunnels = securetunnels.AsyncSecuretunnelsResource(self) - self.roles = roles.AsyncRolesResource(self) - self.policies = policies.AsyncPoliciesResource(self) - self.chats = chats.AsyncChatsResource(self) - self.datasources = datasources.AsyncDatasourcesResource(self) - self.bots = bots.AsyncBotsResource(self) - self.auth = auth.AsyncAuthResource(self) - self.answers = answers.AsyncAnswersResource(self) - self.sqls = sqls.AsyncSqlsResource(self) - self.caches = caches.AsyncCachesResource(self) - self.integration = integration.AsyncIntegrationResource(self) - self.business_glossary = business_glossary.AsyncBusinessGlossaryResource(self) - self.preferences = preferences.AsyncPreferencesResource(self) - self.trainings = trainings.AsyncTrainingsResource(self) - self.project = project.AsyncProjectResource(self) - self.scores = scores.AsyncScoresResource(self) - self.files = files.AsyncFilesResource(self) - self.dataframes = dataframes.AsyncDataframesResource(self) - self.polish = polish.AsyncPolishResource(self) - self.user = user.AsyncUserResource(self) - self.ats = ats.AsyncATSResource(self) - self.with_raw_response = AsyncAsktableWithRawResponse(self) - self.with_streaming_response = AsyncAsktableWithStreamedResponse(self) + @cached_property + def sys(self) -> AsyncSysResource: + from .resources.sys import AsyncSysResource + + return AsyncSysResource(self) + + @cached_property + def datasources(self) -> AsyncDatasourcesResource: + """数据源管理""" + from .resources.datasources import AsyncDatasourcesResource + + return AsyncDatasourcesResource(self) + + @cached_property + def auth(self) -> AsyncAuthResource: + """AskTable 系统认证管理""" + from .resources.auth import AsyncAuthResource + + return AsyncAuthResource(self) + + @cached_property + def integration(self) -> AsyncIntegrationResource: + """与第三方平台集成""" + from .resources.integration import AsyncIntegrationResource + + return AsyncIntegrationResource(self) + + @cached_property + def project(self) -> AsyncProjectResource: + """我的项目""" + from .resources.project import AsyncProjectResource + + return AsyncProjectResource(self) + + @cached_property + def scores(self) -> AsyncScoresResource: + """评分""" + from .resources.scores import AsyncScoresResource + + return AsyncScoresResource(self) + + @cached_property + def files(self) -> AsyncFilesResource: + """数据源管理""" + from .resources.files import AsyncFilesResource + + return AsyncFilesResource(self) + + @cached_property + def dataframes(self) -> AsyncDataframesResource: + from .resources.dataframes import AsyncDataframesResource + + return AsyncDataframesResource(self) + + @cached_property + def polish(self) -> AsyncPolishResource: + """润色""" + from .resources.polish import AsyncPolishResource + + return AsyncPolishResource(self) + + @cached_property + def user(self) -> AsyncUserResource: + from .resources.user import AsyncUserResource + + return AsyncUserResource(self) + + @cached_property + def with_raw_response(self) -> AsyncAsktableWithRawResponse: + return AsyncAsktableWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAsktableWithStreamedResponse: + return AsyncAsktableWithStreamedResponse(self) @property @override @@ -405,9 +467,9 @@ def copy( *, api_key: str | None = None, base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, - max_retries: int | NotGiven = NOT_GIVEN, + max_retries: int | NotGiven = not_given, default_headers: Mapping[str, str] | None = None, set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -486,113 +548,299 @@ def _make_status_error( class AsktableWithRawResponse: + _client: Asktable + def __init__(self, client: Asktable) -> None: - self.sys = sys.SysResourceWithRawResponse(client.sys) - self.securetunnels = securetunnels.SecuretunnelsResourceWithRawResponse(client.securetunnels) - self.roles = roles.RolesResourceWithRawResponse(client.roles) - self.policies = policies.PoliciesResourceWithRawResponse(client.policies) - self.chats = chats.ChatsResourceWithRawResponse(client.chats) - self.datasources = datasources.DatasourcesResourceWithRawResponse(client.datasources) - self.bots = bots.BotsResourceWithRawResponse(client.bots) - self.auth = auth.AuthResourceWithRawResponse(client.auth) - self.answers = answers.AnswersResourceWithRawResponse(client.answers) - self.sqls = sqls.SqlsResourceWithRawResponse(client.sqls) - self.caches = caches.CachesResourceWithRawResponse(client.caches) - self.integration = integration.IntegrationResourceWithRawResponse(client.integration) - self.business_glossary = business_glossary.BusinessGlossaryResourceWithRawResponse(client.business_glossary) - self.preferences = preferences.PreferencesResourceWithRawResponse(client.preferences) - self.trainings = trainings.TrainingsResourceWithRawResponse(client.trainings) - self.project = project.ProjectResourceWithRawResponse(client.project) - self.scores = scores.ScoresResourceWithRawResponse(client.scores) - self.files = files.FilesResourceWithRawResponse(client.files) - self.dataframes = dataframes.DataframesResourceWithRawResponse(client.dataframes) - self.polish = polish.PolishResourceWithRawResponse(client.polish) - self.user = user.UserResourceWithRawResponse(client.user) - self.ats = ats.ATSResourceWithRawResponse(client.ats) + self._client = client + + @cached_property + def sys(self) -> sys.SysResourceWithRawResponse: + from .resources.sys import SysResourceWithRawResponse + + return SysResourceWithRawResponse(self._client.sys) + + @cached_property + def datasources(self) -> datasources.DatasourcesResourceWithRawResponse: + """数据源管理""" + from .resources.datasources import DatasourcesResourceWithRawResponse + + return DatasourcesResourceWithRawResponse(self._client.datasources) + + @cached_property + def auth(self) -> auth.AuthResourceWithRawResponse: + """AskTable 系统认证管理""" + from .resources.auth import AuthResourceWithRawResponse + + return AuthResourceWithRawResponse(self._client.auth) + + @cached_property + def integration(self) -> integration.IntegrationResourceWithRawResponse: + """与第三方平台集成""" + from .resources.integration import IntegrationResourceWithRawResponse + + return IntegrationResourceWithRawResponse(self._client.integration) + + @cached_property + def project(self) -> project.ProjectResourceWithRawResponse: + """我的项目""" + from .resources.project import ProjectResourceWithRawResponse + + return ProjectResourceWithRawResponse(self._client.project) + + @cached_property + def scores(self) -> scores.ScoresResourceWithRawResponse: + """评分""" + from .resources.scores import ScoresResourceWithRawResponse + + return ScoresResourceWithRawResponse(self._client.scores) + + @cached_property + def files(self) -> files.FilesResourceWithRawResponse: + """数据源管理""" + from .resources.files import FilesResourceWithRawResponse + + return FilesResourceWithRawResponse(self._client.files) + + @cached_property + def dataframes(self) -> dataframes.DataframesResourceWithRawResponse: + from .resources.dataframes import DataframesResourceWithRawResponse + + return DataframesResourceWithRawResponse(self._client.dataframes) + + @cached_property + def polish(self) -> polish.PolishResourceWithRawResponse: + """润色""" + from .resources.polish import PolishResourceWithRawResponse + + return PolishResourceWithRawResponse(self._client.polish) + + @cached_property + def user(self) -> user.UserResourceWithRawResponse: + from .resources.user import UserResourceWithRawResponse + + return UserResourceWithRawResponse(self._client.user) class AsyncAsktableWithRawResponse: + _client: AsyncAsktable + def __init__(self, client: AsyncAsktable) -> None: - self.sys = sys.AsyncSysResourceWithRawResponse(client.sys) - self.securetunnels = securetunnels.AsyncSecuretunnelsResourceWithRawResponse(client.securetunnels) - self.roles = roles.AsyncRolesResourceWithRawResponse(client.roles) - self.policies = policies.AsyncPoliciesResourceWithRawResponse(client.policies) - self.chats = chats.AsyncChatsResourceWithRawResponse(client.chats) - self.datasources = datasources.AsyncDatasourcesResourceWithRawResponse(client.datasources) - self.bots = bots.AsyncBotsResourceWithRawResponse(client.bots) - self.auth = auth.AsyncAuthResourceWithRawResponse(client.auth) - self.answers = answers.AsyncAnswersResourceWithRawResponse(client.answers) - self.sqls = sqls.AsyncSqlsResourceWithRawResponse(client.sqls) - self.caches = caches.AsyncCachesResourceWithRawResponse(client.caches) - self.integration = integration.AsyncIntegrationResourceWithRawResponse(client.integration) - self.business_glossary = business_glossary.AsyncBusinessGlossaryResourceWithRawResponse( - client.business_glossary - ) - self.preferences = preferences.AsyncPreferencesResourceWithRawResponse(client.preferences) - self.trainings = trainings.AsyncTrainingsResourceWithRawResponse(client.trainings) - self.project = project.AsyncProjectResourceWithRawResponse(client.project) - self.scores = scores.AsyncScoresResourceWithRawResponse(client.scores) - self.files = files.AsyncFilesResourceWithRawResponse(client.files) - self.dataframes = dataframes.AsyncDataframesResourceWithRawResponse(client.dataframes) - self.polish = polish.AsyncPolishResourceWithRawResponse(client.polish) - self.user = user.AsyncUserResourceWithRawResponse(client.user) - self.ats = ats.AsyncATSResourceWithRawResponse(client.ats) + self._client = client + + @cached_property + def sys(self) -> sys.AsyncSysResourceWithRawResponse: + from .resources.sys import AsyncSysResourceWithRawResponse + + return AsyncSysResourceWithRawResponse(self._client.sys) + + @cached_property + def datasources(self) -> datasources.AsyncDatasourcesResourceWithRawResponse: + """数据源管理""" + from .resources.datasources import AsyncDatasourcesResourceWithRawResponse + + return AsyncDatasourcesResourceWithRawResponse(self._client.datasources) + + @cached_property + def auth(self) -> auth.AsyncAuthResourceWithRawResponse: + """AskTable 系统认证管理""" + from .resources.auth import AsyncAuthResourceWithRawResponse + + return AsyncAuthResourceWithRawResponse(self._client.auth) + + @cached_property + def integration(self) -> integration.AsyncIntegrationResourceWithRawResponse: + """与第三方平台集成""" + from .resources.integration import AsyncIntegrationResourceWithRawResponse + + return AsyncIntegrationResourceWithRawResponse(self._client.integration) + + @cached_property + def project(self) -> project.AsyncProjectResourceWithRawResponse: + """我的项目""" + from .resources.project import AsyncProjectResourceWithRawResponse + + return AsyncProjectResourceWithRawResponse(self._client.project) + + @cached_property + def scores(self) -> scores.AsyncScoresResourceWithRawResponse: + """评分""" + from .resources.scores import AsyncScoresResourceWithRawResponse + + return AsyncScoresResourceWithRawResponse(self._client.scores) + + @cached_property + def files(self) -> files.AsyncFilesResourceWithRawResponse: + """数据源管理""" + from .resources.files import AsyncFilesResourceWithRawResponse + + return AsyncFilesResourceWithRawResponse(self._client.files) + + @cached_property + def dataframes(self) -> dataframes.AsyncDataframesResourceWithRawResponse: + from .resources.dataframes import AsyncDataframesResourceWithRawResponse + + return AsyncDataframesResourceWithRawResponse(self._client.dataframes) + + @cached_property + def polish(self) -> polish.AsyncPolishResourceWithRawResponse: + """润色""" + from .resources.polish import AsyncPolishResourceWithRawResponse + + return AsyncPolishResourceWithRawResponse(self._client.polish) + + @cached_property + def user(self) -> user.AsyncUserResourceWithRawResponse: + from .resources.user import AsyncUserResourceWithRawResponse + + return AsyncUserResourceWithRawResponse(self._client.user) class AsktableWithStreamedResponse: + _client: Asktable + def __init__(self, client: Asktable) -> None: - self.sys = sys.SysResourceWithStreamingResponse(client.sys) - self.securetunnels = securetunnels.SecuretunnelsResourceWithStreamingResponse(client.securetunnels) - self.roles = roles.RolesResourceWithStreamingResponse(client.roles) - self.policies = policies.PoliciesResourceWithStreamingResponse(client.policies) - self.chats = chats.ChatsResourceWithStreamingResponse(client.chats) - self.datasources = datasources.DatasourcesResourceWithStreamingResponse(client.datasources) - self.bots = bots.BotsResourceWithStreamingResponse(client.bots) - self.auth = auth.AuthResourceWithStreamingResponse(client.auth) - self.answers = answers.AnswersResourceWithStreamingResponse(client.answers) - self.sqls = sqls.SqlsResourceWithStreamingResponse(client.sqls) - self.caches = caches.CachesResourceWithStreamingResponse(client.caches) - self.integration = integration.IntegrationResourceWithStreamingResponse(client.integration) - self.business_glossary = business_glossary.BusinessGlossaryResourceWithStreamingResponse( - client.business_glossary - ) - self.preferences = preferences.PreferencesResourceWithStreamingResponse(client.preferences) - self.trainings = trainings.TrainingsResourceWithStreamingResponse(client.trainings) - self.project = project.ProjectResourceWithStreamingResponse(client.project) - self.scores = scores.ScoresResourceWithStreamingResponse(client.scores) - self.files = files.FilesResourceWithStreamingResponse(client.files) - self.dataframes = dataframes.DataframesResourceWithStreamingResponse(client.dataframes) - self.polish = polish.PolishResourceWithStreamingResponse(client.polish) - self.user = user.UserResourceWithStreamingResponse(client.user) - self.ats = ats.ATSResourceWithStreamingResponse(client.ats) + self._client = client + + @cached_property + def sys(self) -> sys.SysResourceWithStreamingResponse: + from .resources.sys import SysResourceWithStreamingResponse + + return SysResourceWithStreamingResponse(self._client.sys) + + @cached_property + def datasources(self) -> datasources.DatasourcesResourceWithStreamingResponse: + """数据源管理""" + from .resources.datasources import DatasourcesResourceWithStreamingResponse + + return DatasourcesResourceWithStreamingResponse(self._client.datasources) + + @cached_property + def auth(self) -> auth.AuthResourceWithStreamingResponse: + """AskTable 系统认证管理""" + from .resources.auth import AuthResourceWithStreamingResponse + + return AuthResourceWithStreamingResponse(self._client.auth) + + @cached_property + def integration(self) -> integration.IntegrationResourceWithStreamingResponse: + """与第三方平台集成""" + from .resources.integration import IntegrationResourceWithStreamingResponse + + return IntegrationResourceWithStreamingResponse(self._client.integration) + + @cached_property + def project(self) -> project.ProjectResourceWithStreamingResponse: + """我的项目""" + from .resources.project import ProjectResourceWithStreamingResponse + + return ProjectResourceWithStreamingResponse(self._client.project) + + @cached_property + def scores(self) -> scores.ScoresResourceWithStreamingResponse: + """评分""" + from .resources.scores import ScoresResourceWithStreamingResponse + + return ScoresResourceWithStreamingResponse(self._client.scores) + + @cached_property + def files(self) -> files.FilesResourceWithStreamingResponse: + """数据源管理""" + from .resources.files import FilesResourceWithStreamingResponse + + return FilesResourceWithStreamingResponse(self._client.files) + + @cached_property + def dataframes(self) -> dataframes.DataframesResourceWithStreamingResponse: + from .resources.dataframes import DataframesResourceWithStreamingResponse + + return DataframesResourceWithStreamingResponse(self._client.dataframes) + + @cached_property + def polish(self) -> polish.PolishResourceWithStreamingResponse: + """润色""" + from .resources.polish import PolishResourceWithStreamingResponse + + return PolishResourceWithStreamingResponse(self._client.polish) + + @cached_property + def user(self) -> user.UserResourceWithStreamingResponse: + from .resources.user import UserResourceWithStreamingResponse + + return UserResourceWithStreamingResponse(self._client.user) class AsyncAsktableWithStreamedResponse: + _client: AsyncAsktable + def __init__(self, client: AsyncAsktable) -> None: - self.sys = sys.AsyncSysResourceWithStreamingResponse(client.sys) - self.securetunnels = securetunnels.AsyncSecuretunnelsResourceWithStreamingResponse(client.securetunnels) - self.roles = roles.AsyncRolesResourceWithStreamingResponse(client.roles) - self.policies = policies.AsyncPoliciesResourceWithStreamingResponse(client.policies) - self.chats = chats.AsyncChatsResourceWithStreamingResponse(client.chats) - self.datasources = datasources.AsyncDatasourcesResourceWithStreamingResponse(client.datasources) - self.bots = bots.AsyncBotsResourceWithStreamingResponse(client.bots) - self.auth = auth.AsyncAuthResourceWithStreamingResponse(client.auth) - self.answers = answers.AsyncAnswersResourceWithStreamingResponse(client.answers) - self.sqls = sqls.AsyncSqlsResourceWithStreamingResponse(client.sqls) - self.caches = caches.AsyncCachesResourceWithStreamingResponse(client.caches) - self.integration = integration.AsyncIntegrationResourceWithStreamingResponse(client.integration) - self.business_glossary = business_glossary.AsyncBusinessGlossaryResourceWithStreamingResponse( - client.business_glossary - ) - self.preferences = preferences.AsyncPreferencesResourceWithStreamingResponse(client.preferences) - self.trainings = trainings.AsyncTrainingsResourceWithStreamingResponse(client.trainings) - self.project = project.AsyncProjectResourceWithStreamingResponse(client.project) - self.scores = scores.AsyncScoresResourceWithStreamingResponse(client.scores) - self.files = files.AsyncFilesResourceWithStreamingResponse(client.files) - self.dataframes = dataframes.AsyncDataframesResourceWithStreamingResponse(client.dataframes) - self.polish = polish.AsyncPolishResourceWithStreamingResponse(client.polish) - self.user = user.AsyncUserResourceWithStreamingResponse(client.user) - self.ats = ats.AsyncATSResourceWithStreamingResponse(client.ats) + self._client = client + + @cached_property + def sys(self) -> sys.AsyncSysResourceWithStreamingResponse: + from .resources.sys import AsyncSysResourceWithStreamingResponse + + return AsyncSysResourceWithStreamingResponse(self._client.sys) + + @cached_property + def datasources(self) -> datasources.AsyncDatasourcesResourceWithStreamingResponse: + """数据源管理""" + from .resources.datasources import AsyncDatasourcesResourceWithStreamingResponse + + return AsyncDatasourcesResourceWithStreamingResponse(self._client.datasources) + + @cached_property + def auth(self) -> auth.AsyncAuthResourceWithStreamingResponse: + """AskTable 系统认证管理""" + from .resources.auth import AsyncAuthResourceWithStreamingResponse + + return AsyncAuthResourceWithStreamingResponse(self._client.auth) + + @cached_property + def integration(self) -> integration.AsyncIntegrationResourceWithStreamingResponse: + """与第三方平台集成""" + from .resources.integration import AsyncIntegrationResourceWithStreamingResponse + + return AsyncIntegrationResourceWithStreamingResponse(self._client.integration) + + @cached_property + def project(self) -> project.AsyncProjectResourceWithStreamingResponse: + """我的项目""" + from .resources.project import AsyncProjectResourceWithStreamingResponse + + return AsyncProjectResourceWithStreamingResponse(self._client.project) + + @cached_property + def scores(self) -> scores.AsyncScoresResourceWithStreamingResponse: + """评分""" + from .resources.scores import AsyncScoresResourceWithStreamingResponse + + return AsyncScoresResourceWithStreamingResponse(self._client.scores) + + @cached_property + def files(self) -> files.AsyncFilesResourceWithStreamingResponse: + """数据源管理""" + from .resources.files import AsyncFilesResourceWithStreamingResponse + + return AsyncFilesResourceWithStreamingResponse(self._client.files) + + @cached_property + def dataframes(self) -> dataframes.AsyncDataframesResourceWithStreamingResponse: + from .resources.dataframes import AsyncDataframesResourceWithStreamingResponse + + return AsyncDataframesResourceWithStreamingResponse(self._client.dataframes) + + @cached_property + def polish(self) -> polish.AsyncPolishResourceWithStreamingResponse: + """润色""" + from .resources.polish import AsyncPolishResourceWithStreamingResponse + + return AsyncPolishResourceWithStreamingResponse(self._client.polish) + + @cached_property + def user(self) -> user.AsyncUserResourceWithStreamingResponse: + from .resources.user import AsyncUserResourceWithStreamingResponse + + return AsyncUserResourceWithStreamingResponse(self._client.user) Client = Asktable diff --git a/src/asktable/_compat.py b/src/asktable/_compat.py index 92d9ee61..e6690a4f 100644 --- a/src/asktable/_compat.py +++ b/src/asktable/_compat.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload from datetime import date, datetime -from typing_extensions import Self, Literal +from typing_extensions import Self, Literal, TypedDict import pydantic from pydantic.fields import FieldInfo @@ -12,14 +12,13 @@ _T = TypeVar("_T") _ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) -# --------------- Pydantic v2 compatibility --------------- +# --------------- Pydantic v2, v3 compatibility --------------- # Pyright incorrectly reports some of our functions as overriding a method when they don't # pyright: reportIncompatibleMethodOverride=false -PYDANTIC_V2 = pydantic.VERSION.startswith("2.") +PYDANTIC_V1 = pydantic.VERSION.startswith("1.") -# v1 re-exports if TYPE_CHECKING: def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 @@ -44,90 +43,96 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 ... else: - if PYDANTIC_V2: - from pydantic.v1.typing import ( + # v1 re-exports + if PYDANTIC_V1: + from pydantic.typing import ( get_args as get_args, is_union as is_union, get_origin as get_origin, is_typeddict as is_typeddict, is_literal_type as is_literal_type, ) - from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime else: - from pydantic.typing import ( + from ._utils import ( get_args as get_args, is_union as is_union, get_origin as get_origin, + parse_date as parse_date, is_typeddict as is_typeddict, + parse_datetime as parse_datetime, is_literal_type as is_literal_type, ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime # refactored config if TYPE_CHECKING: from pydantic import ConfigDict as ConfigDict else: - if PYDANTIC_V2: - from pydantic import ConfigDict - else: + if PYDANTIC_V1: # TODO: provide an error message here? ConfigDict = None + else: + from pydantic import ConfigDict as ConfigDict # renamed methods / properties def parse_obj(model: type[_ModelT], value: object) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(value) - else: + if PYDANTIC_V1: return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + else: + return model.model_validate(value) def field_is_required(field: FieldInfo) -> bool: - if PYDANTIC_V2: - return field.is_required() - return field.required # type: ignore + if PYDANTIC_V1: + return field.required # type: ignore + return field.is_required() def field_get_default(field: FieldInfo) -> Any: value = field.get_default() - if PYDANTIC_V2: - from pydantic_core import PydanticUndefined - - if value == PydanticUndefined: - return None + if PYDANTIC_V1: return value + from pydantic_core import PydanticUndefined + + if value == PydanticUndefined: + return None return value def field_outer_type(field: FieldInfo) -> Any: - if PYDANTIC_V2: - return field.annotation - return field.outer_type_ # type: ignore + if PYDANTIC_V1: + return field.outer_type_ # type: ignore + return field.annotation def get_model_config(model: type[pydantic.BaseModel]) -> Any: - if PYDANTIC_V2: - return model.model_config - return model.__config__ # type: ignore + if PYDANTIC_V1: + return model.__config__ # type: ignore + return model.model_config def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: - if PYDANTIC_V2: - return model.model_fields - return model.__fields__ # type: ignore + if PYDANTIC_V1: + return model.__fields__ # type: ignore + return model.model_fields def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: - if PYDANTIC_V2: - return model.model_copy(deep=deep) - return model.copy(deep=deep) # type: ignore + if PYDANTIC_V1: + return model.copy(deep=deep) # type: ignore + return model.model_copy(deep=deep) def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: - if PYDANTIC_V2: - return model.model_dump_json(indent=indent) - return model.json(indent=indent) # type: ignore + if PYDANTIC_V1: + return model.json(indent=indent) # type: ignore + return model.model_dump_json(indent=indent) + + +class _ModelDumpKwargs(TypedDict, total=False): + by_alias: bool def model_dump( @@ -138,30 +143,33 @@ def model_dump( exclude_defaults: bool = False, warnings: bool = True, mode: Literal["json", "python"] = "python", + by_alias: bool | None = None, ) -> dict[str, Any]: - if PYDANTIC_V2 or hasattr(model, "model_dump"): + if (not PYDANTIC_V1) or hasattr(model, "model_dump"): + kwargs: _ModelDumpKwargs = {} + if by_alias is not None: + kwargs["by_alias"] = by_alias return model.model_dump( mode=mode, exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, # warnings are not supported in Pydantic v1 - warnings=warnings if PYDANTIC_V2 else True, + warnings=True if PYDANTIC_V1 else warnings, + **kwargs, ) return cast( "dict[str, Any]", model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - exclude=exclude, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, + exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) ), ) def model_parse(model: type[_ModelT], data: Any) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(data) - return model.parse_obj(data) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return model.parse_obj(data) # pyright: ignore[reportDeprecated] + return model.model_validate(data) # generic models @@ -170,17 +178,16 @@ def model_parse(model: type[_ModelT], data: Any) -> _ModelT: class GenericModel(pydantic.BaseModel): ... else: - if PYDANTIC_V2: + if PYDANTIC_V1: + import pydantic.generics + + class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... + else: # there no longer needs to be a distinction in v2 but # we still have to create our own subclass to avoid # inconsistent MRO ordering errors class GenericModel(pydantic.BaseModel): ... - else: - import pydantic.generics - - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... - # cached properties if TYPE_CHECKING: diff --git a/src/asktable/_files.py b/src/asktable/_files.py index 25ff804f..76da9e08 100644 --- a/src/asktable/_files.py +++ b/src/asktable/_files.py @@ -3,8 +3,8 @@ import io import os import pathlib -from typing import overload -from typing_extensions import TypeGuard +from typing import Sequence, cast, overload +from typing_extensions import TypeVar, TypeGuard import anyio @@ -17,7 +17,9 @@ HttpxFileContent, HttpxRequestFiles, ) -from ._utils import is_tuple_t, is_mapping_t, is_sequence_t +from ._utils import is_list, is_mapping, is_tuple_t, is_mapping_t, is_sequence_t + +_T = TypeVar("_T") def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: @@ -34,7 +36,7 @@ def assert_is_file_content(obj: object, *, key: str | None = None) -> None: if not is_file_content(obj): prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" raise RuntimeError( - f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead. See https://github.com/DataMini/asktable-python/tree/main#file-uploads" + f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead." ) from None @@ -69,12 +71,12 @@ def _transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], _read_file_content(file[1]), *file[2:]) + return (file[0], read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -def _read_file_content(file: FileContent) -> HttpxFileContent: +def read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return pathlib.Path(file).read_bytes() return file @@ -97,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles elif is_sequence_t(files): files = [(key, await _async_transform_file(file)) for key, file in files] else: - raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") + raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") return files @@ -111,13 +113,61 @@ async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], await _async_read_file_content(file[1]), *file[2:]) + return (file[0], await async_read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -async def _async_read_file_content(file: FileContent) -> HttpxFileContent: +async def async_read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return await anyio.Path(file).read_bytes() return file + + +def deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]]) -> _T: + """Copy only the containers along the given paths. + + Used to guard against mutation by extract_files without copying the entire structure. + Only dicts and lists that lie on a path are copied; everything else + is returned by reference. + + For example, given paths=[["foo", "files", "file"]] and the structure: + { + "foo": { + "bar": {"baz": {}}, + "files": {"file": } + } + } + The root dict, "foo", and "files" are copied (they lie on the path). + "bar" and "baz" are returned by reference (off the path). + """ + return _deepcopy_with_paths(item, paths, 0) + + +def _deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]], index: int) -> _T: + if not paths: + return item + if is_mapping(item): + key_to_paths: dict[str, list[Sequence[str]]] = {} + for path in paths: + if index < len(path): + key_to_paths.setdefault(path[index], []).append(path) + + # if no path continues through this mapping, it won't be mutated and copying it is redundant + if not key_to_paths: + return item + + result = dict(item) + for key, subpaths in key_to_paths.items(): + if key in result: + result[key] = _deepcopy_with_paths(result[key], subpaths, index + 1) + return cast(_T, result) + if is_list(item): + array_paths = [path for path in paths if index < len(path) and path[index] == ""] + + # if no path expects a list here, nothing will be mutated inside it - return by reference + if not array_paths: + return cast(_T, item) + return cast(_T, [_deepcopy_with_paths(entry, array_paths, index + 1) for entry in item]) + return item diff --git a/src/asktable/_models.py b/src/asktable/_models.py index 528d5680..8c5ab260 100644 --- a/src/asktable/_models.py +++ b/src/asktable/_models.py @@ -2,7 +2,21 @@ import os import inspect -from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast +import weakref +from typing import ( + IO, + TYPE_CHECKING, + Any, + Type, + Union, + Generic, + TypeVar, + Callable, + Iterable, + Optional, + AsyncIterable, + cast, +) from datetime import date, datetime from typing_extensions import ( List, @@ -11,7 +25,9 @@ ClassVar, Protocol, Required, + Annotated, ParamSpec, + TypeAlias, TypedDict, TypeGuard, final, @@ -50,7 +66,7 @@ strip_annotated_type, ) from ._compat import ( - PYDANTIC_V2, + PYDANTIC_V1, ConfigDict, GenericModel as BaseGenericModel, get_args, @@ -65,7 +81,15 @@ from ._constants import RAW_RESPONSE_HEADER 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 +else: + try: + from pydantic_core import CoreSchema, core_schema + except ImportError: + CoreSchema = None + core_schema = None __all__ = ["BaseModel", "GenericModel"] @@ -81,11 +105,7 @@ class _ConfigProtocol(Protocol): class BaseModel(pydantic.BaseModel): - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) - ) - else: + if PYDANTIC_V1: @property @override @@ -95,6 +115,10 @@ def model_fields_set(self) -> set[str]: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] extra: Any = pydantic.Extra.allow # type: ignore + else: + model_config: ClassVar[ConfigDict] = ConfigDict( + extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) + ) def to_dict( self, @@ -208,28 +232,32 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] else: fields_values[name] = field_get_default(field) + extra_field_type = _get_extra_fields_type(__cls) + _extra = {} for key, value in values.items(): if key not in model_fields: - if PYDANTIC_V2: - _extra[key] = value - else: + parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value + + if PYDANTIC_V1: _fields_set.add(key) - fields_values[key] = value + fields_values[key] = parsed + else: + _extra[key] = parsed object.__setattr__(m, "__dict__", fields_values) - if PYDANTIC_V2: - # these properties are copied from Pydantic's `model_construct()` method - object.__setattr__(m, "__pydantic_private__", None) - object.__setattr__(m, "__pydantic_extra__", _extra) - object.__setattr__(m, "__pydantic_fields_set__", _fields_set) - else: + if PYDANTIC_V1: # init_private_attributes() does not exist in v2 m._init_private_attributes() # type: ignore # copied from Pydantic v1's `construct()` method object.__setattr__(m, "__fields_set__", _fields_set) + else: + # these properties are copied from Pydantic's `model_construct()` method + object.__setattr__(m, "__pydantic_private__", None) + object.__setattr__(m, "__pydantic_extra__", _extra) + object.__setattr__(m, "__pydantic_fields_set__", _fields_set) return m @@ -239,7 +267,7 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] # although not in practice model_construct = construct - if not PYDANTIC_V2: + if PYDANTIC_V1: # we define aliases for some of the new pydantic v2 methods so # that we can just document these methods without having to specify # a specific pydantic version as some users may not know which @@ -252,13 +280,15 @@ def model_dump( mode: Literal["json", "python"] | str = "python", include: IncEx | None = None, exclude: IncEx | None = None, - by_alias: bool = False, + context: Any | None = None, + by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, - context: dict[str, Any] | None = None, + fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, ) -> dict[str, Any]: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump @@ -267,16 +297,24 @@ def model_dump( Args: mode: The mode in which `to_python` should run. - If mode is 'json', the dictionary will only contain JSON serializable types. - If mode is 'python', the dictionary may contain any Python objects. - include: A list of fields to include in the output. - exclude: A list of fields to exclude from the output. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. by_alias: Whether to use the field's alias in the dictionary key if defined. - exclude_unset: Whether to exclude fields that are unset or None from the output. - exclude_defaults: Whether to exclude fields that are set to their default value from the output. - exclude_none: Whether to exclude fields that have a value of `None` from the output. - round_trip: Whether to enable serialization and deserialization round-trip support. - warnings: Whether to log warnings when invalid fields are encountered. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. Returns: A dictionary representation of the model. @@ -291,31 +329,38 @@ def model_dump( raise ValueError("context is only supported in Pydantic v2") if serialize_as_any != False: raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + 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] include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias if by_alias is not None else False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, exclude_none=exclude_none, ) - return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped + return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped @override def model_dump_json( self, *, indent: int | None = None, + ensure_ascii: bool = False, include: IncEx | None = None, exclude: IncEx | None = None, - by_alias: bool = False, + context: Any | None = None, + by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, - context: dict[str, Any] | None = None, + fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, ) -> str: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json @@ -344,25 +389,101 @@ def model_dump_json( raise ValueError("context is only supported in Pydantic v2") if serialize_as_any != False: raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") + if ensure_ascii != False: + 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] indent=indent, include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias if by_alias is not None else False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, exclude_none=exclude_none, ) +class _EagerIterable(list[_T], Generic[_T]): + """ + Accepts any Iterable[T] input (including generators), consumes it + eagerly, and validates all items upfront. + + Validation preserves the original container type where possible + (e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON) + always emits a list — round-tripping through model_dump() will not + restore the original container type. + """ + + @classmethod + def __get_pydantic_core_schema__( + cls, + source_type: Any, + handler: GetCoreSchemaHandler, + ) -> CoreSchema: + (item_type,) = get_args(source_type) or (Any,) + item_schema: CoreSchema = handler.generate_schema(item_type) + list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema) + + return core_schema.no_info_wrap_validator_function( + cls._validate, + list_of_items_schema, + serialization=core_schema.plain_serializer_function_ser_schema( + cls._serialize, + info_arg=False, + ), + ) + + @staticmethod + def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any: + original_type: type[Any] = type(v) + + # Normalize to list so list_schema can validate each item + if isinstance(v, list): + items: list[_T] = v + else: + try: + items = list(v) + except TypeError as e: + raise TypeError("Value is not iterable") from e + + # Validate items against the inner schema + validated: list[_T] = handler(items) + + # Reconstruct original container type + if original_type is list: + return validated + # str(list) produces the list's repr, not a string built from items, + # so skip reconstruction for str and its subclasses. + if issubclass(original_type, str): + return validated + try: + return original_type(validated) + except (TypeError, ValueError): + # If the type cannot be reconstructed, just return the validated list + return validated + + @staticmethod + def _serialize(v: Iterable[_T]) -> list[_T]: + """Always serialize as a list so Pydantic's JSON encoder is happy.""" + if isinstance(v, list): + return v + return list(v) + + +EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable] + + def _construct_field(value: object, field: FieldInfo, key: str) -> object: if value is None: return field_get_default(field) - if PYDANTIC_V2: - type_ = field.annotation - else: + if PYDANTIC_V1: type_ = cast(type, field.outer_type_) # type: ignore + else: + type_ = field.annotation # type: ignore if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") @@ -370,6 +491,23 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) +def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: + if PYDANTIC_V1: + # TODO + return None + + schema = cls.__pydantic_core_schema__ + if schema["type"] == "model": + fields = schema["schema"] + 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] + + return None + + def is_basemodel(type_: type) -> bool: """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" if is_union(type_): @@ -439,7 +577,7 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` - if metadata is not None: + if metadata is not None and len(metadata) > 0: meta: tuple[Any, ...] = tuple(metadata) elif is_annotated_type(type_): meta = get_args(type_)[1:] @@ -546,6 +684,9 @@ class CachedDiscriminatorType(Protocol): __discriminator__: DiscriminatorDetails +DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() + + class DiscriminatorDetails: field_name: str """The name of the discriminator field in the variant class, e.g. @@ -588,8 +729,9 @@ def __init__( def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - if isinstance(union, CachedDiscriminatorType): - return union.__discriminator__ + cached = DISCRIMINATOR_CACHE.get(union) + if cached is not None: + return cached discriminator_field_name: str | None = None @@ -607,30 +749,30 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, for variant in get_args(union): variant = strip_annotated_type(variant) if is_basemodel_type(variant): - if PYDANTIC_V2: - field = _extract_field_schema_pv2(variant, discriminator_field_name) - if not field: + if PYDANTIC_V1: + field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + if not field_info: continue # Note: if one variant defines an alias then they all should - discriminator_alias = field.get("serialization_alias") - - field_schema = field["schema"] + discriminator_alias = field_info.alias - if field_schema["type"] == "literal": - for entry in cast("LiteralSchema", field_schema)["expected"]: + if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): + for entry in get_args(annotation): if isinstance(entry, str): mapping[entry] = variant else: - field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - if not field_info: + field = _extract_field_schema_pv2(variant, discriminator_field_name) + if not field: continue # Note: if one variant defines an alias then they all should - discriminator_alias = field_info.alias + discriminator_alias = field.get("serialization_alias") - if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): - for entry in get_args(annotation): + field_schema = field["schema"] + + if field_schema["type"] == "literal": + for entry in cast("LiteralSchema", field_schema)["expected"]: if isinstance(entry, str): mapping[entry] = variant @@ -642,7 +784,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, discriminator_field=discriminator_field_name, discriminator_alias=discriminator_alias, ) - cast(CachedDiscriminatorType, union).__discriminator__ = details + DISCRIMINATOR_CACHE.setdefault(union, details) return details @@ -693,7 +835,7 @@ class GenericModel(BaseGenericModel, BaseModel): pass -if PYDANTIC_V2: +if not PYDANTIC_V1: from pydantic import TypeAdapter as _TypeAdapter _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) @@ -738,6 +880,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): timeout: float | Timeout | None files: HttpxRequestFiles | None idempotency_key: str + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] json_data: Body extra_json: AnyMapping follow_redirects: bool @@ -756,17 +899,18 @@ class FinalRequestOptions(pydantic.BaseModel): post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() follow_redirects: Union[bool, None] = None + content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None # It should be noted that we cannot use `json` here as that would override # a BaseModel method in an incompatible fashion. json_data: Union[Body, None] = None extra_json: Union[AnyMapping, None] = None - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) - else: + if PYDANTIC_V1: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] arbitrary_types_allowed: bool = True + else: + model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) def get_max_retries(self, max_retries: int) -> int: if isinstance(self.max_retries, NotGiven): @@ -799,9 +943,9 @@ def construct( # type: ignore key: strip_not_given(value) for key, value in values.items() } - if PYDANTIC_V2: - return super().model_construct(_fields_set, **kwargs) - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + return super().model_construct(_fields_set, **kwargs) if not TYPE_CHECKING: # type checkers incorrectly complain about this assignment diff --git a/src/asktable/_qs.py b/src/asktable/_qs.py index 274320ca..4127c19c 100644 --- a/src/asktable/_qs.py +++ b/src/asktable/_qs.py @@ -2,17 +2,13 @@ from typing import Any, List, Tuple, Union, Mapping, TypeVar from urllib.parse import parse_qs, urlencode -from typing_extensions import Literal, get_args +from typing_extensions import get_args -from ._types import NOT_GIVEN, NotGiven, NotGivenOr +from ._types import NotGiven, ArrayFormat, NestedFormat, not_given from ._utils import flatten _T = TypeVar("_T") - -ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] -NestedFormat = Literal["dots", "brackets"] - PrimitiveData = Union[str, int, float, bool, None] # this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] # https://github.com/microsoft/pyright/issues/3555 @@ -41,8 +37,8 @@ def stringify( self, params: Params, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> str: return urlencode( self.stringify_items( @@ -56,8 +52,8 @@ def stringify_items( self, params: Params, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> list[tuple[str, str]]: opts = Options( qs=self, @@ -101,7 +97,10 @@ def _stringify_item( items.extend(self._stringify_item(key, item, opts)) return items elif array_format == "indices": - raise NotImplementedError("The array indices format is not supported yet") + items = [] + for i, item in enumerate(value): + items.extend(self._stringify_item(f"{key}[{i}]", item, opts)) + return items elif array_format == "brackets": items = [] key = key + "[]" @@ -143,8 +142,8 @@ def __init__( self, qs: Querystring = _qs, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> None: self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/src/asktable/_response.py b/src/asktable/_response.py index 0c91a6f9..de559384 100644 --- a/src/asktable/_response.py +++ b/src/asktable/_response.py @@ -152,6 +152,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: ), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -162,6 +163,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -175,6 +177,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) diff --git a/src/asktable/_streaming.py b/src/asktable/_streaming.py index d37e4a40..978574ca 100644 --- a/src/asktable/_streaming.py +++ b/src/asktable/_streaming.py @@ -4,7 +4,7 @@ import json import inspect from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast +from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable import httpx @@ -13,6 +13,7 @@ if TYPE_CHECKING: from ._client import Asktable, AsyncAsktable + from ._models import FinalRequestOptions _T = TypeVar("_T") @@ -22,7 +23,7 @@ class Stream(Generic[_T]): """Provides the core interface to iterate over a synchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEBytesDecoder def __init__( @@ -31,10 +32,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: Asktable, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() @@ -54,12 +57,12 @@ def __stream__(self) -> Iterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # Ensure the entire stream is consumed - for _sse in iterator: - ... + try: + for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() def __enter__(self) -> Self: return self @@ -85,7 +88,7 @@ class AsyncStream(Generic[_T]): """Provides the core interface to iterate over an asynchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEDecoder | SSEBytesDecoder def __init__( @@ -94,10 +97,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: AsyncAsktable, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() @@ -118,12 +123,12 @@ async def __stream__(self) -> AsyncIterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - async for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # Ensure the entire stream is consumed - async for _sse in iterator: - ... + try: + async for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() async def __aenter__(self) -> Self: return self diff --git a/src/asktable/_types.py b/src/asktable/_types.py index 6a08b156..5a264f62 100644 --- a/src/asktable/_types.py +++ b/src/asktable/_types.py @@ -13,10 +13,23 @@ Mapping, TypeVar, Callable, + Iterable, + Iterator, Optional, Sequence, + AsyncIterable, +) +from typing_extensions import ( + Set, + Literal, + Protocol, + TypeAlias, + TypedDict, + SupportsIndex, + overload, + override, + runtime_checkable, ) -from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable import httpx import pydantic @@ -34,6 +47,9 @@ ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) _T = TypeVar("_T") +ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] +NestedFormat = Literal["dots", "brackets"] + # Approximates httpx internal ProxiesTypes and RequestFiles types # while adding support for `PathLike` instances @@ -45,6 +61,13 @@ else: Base64FileInput = Union[IO[bytes], PathLike] FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. + + +# Used for sending raw binary data / streaming data in request bodies +# e.g. for file uploads without multipart encoding +BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]] +AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]] + FileTypes = Union[ # file (or bytes) FileContent, @@ -106,18 +129,21 @@ class RequestOptions(TypedDict, total=False): # Sentinel class used until PEP 0661 is accepted class NotGiven: """ - A sentinel singleton class used to distinguish omitted keyword arguments - from those passed in with the value None (which may have different behavior). + For parameters with a meaningful None value, we need to distinguish between + the user explicitly passing None, and the user not passing the parameter at + all. + + User code shouldn't need to use not_given directly. For example: ```py - def get(timeout: Union[int, NotGiven, None] = NotGiven()) -> Response: ... + def create(timeout: Timeout | None | NotGiven = not_given): ... - get(timeout=1) # 1s timeout - get(timeout=None) # No timeout - get() # Default timeout behavior, which may not be statically known at the method definition. + create(timeout=1) # 1s timeout + create(timeout=None) # No timeout + create() # Default timeout behavior ``` """ @@ -129,13 +155,14 @@ def __repr__(self) -> str: return "NOT_GIVEN" -NotGivenOr = Union[_T, NotGiven] +not_given = NotGiven() +# for backwards compatibility: NOT_GIVEN = NotGiven() class Omit: - """In certain situations you need to be able to represent a case where a default value has - to be explicitly removed and `None` is not an appropriate substitute, for example: + """ + To explicitly omit something from being sent in a request, use `omit`. ```py # as the default `Content-Type` header is `application/json` that will be sent @@ -145,8 +172,8 @@ class Omit: # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' client.post(..., headers={"Content-Type": "multipart/form-data"}) - # instead you can remove the default `application/json` header by passing Omit - client.post(..., headers={"Content-Type": Omit()}) + # instead you can remove the default `application/json` header by passing omit + client.post(..., headers={"Content-Type": omit}) ``` """ @@ -154,6 +181,9 @@ def __bool__(self) -> Literal[False]: return False +omit = Omit() + + @runtime_checkable class ModelBuilderProtocol(Protocol): @classmethod @@ -217,3 +247,27 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth follow_redirects: bool + + +_T_co = TypeVar("_T_co", covariant=True) + + +if TYPE_CHECKING: + # This works because str.__contains__ does not accept object (either in typeshed or at runtime) + # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + # + # Note: index() and count() methods are intentionally omitted to allow pyright to properly + # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. + class SequenceNotStr(Protocol[_T_co]): + @overload + def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... + @overload + def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... + def __contains__(self, value: object, /) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self) -> Iterator[_T_co]: ... + def __reversed__(self) -> Iterator[_T_co]: ... +else: + # just point this to a normal `Sequence` at runtime to avoid having to special case + # deserializing our custom sequence type + SequenceNotStr = Sequence diff --git a/src/asktable/_utils/__init__.py b/src/asktable/_utils/__init__.py index d4fda26f..1c090e51 100644 --- a/src/asktable/_utils/__init__.py +++ b/src/asktable/_utils/__init__.py @@ -1,3 +1,4 @@ +from ._path import path_template as path_template from ._sync import asyncify as asyncify from ._proxy import LazyProxy as LazyProxy from ._utils import ( @@ -10,7 +11,6 @@ lru_cache as lru_cache, is_mapping as is_mapping, is_tuple_t as is_tuple_t, - parse_date as parse_date, is_iterable as is_iterable, is_sequence as is_sequence, coerce_float as coerce_float, @@ -23,21 +23,27 @@ coerce_boolean as coerce_boolean, coerce_integer as coerce_integer, file_from_path as file_from_path, - parse_datetime as parse_datetime, strip_not_given as strip_not_given, - deepcopy_minimal as deepcopy_minimal, get_async_library as get_async_library, maybe_coerce_float as maybe_coerce_float, get_required_header as get_required_header, maybe_coerce_boolean as maybe_coerce_boolean, maybe_coerce_integer as maybe_coerce_integer, ) +from ._compat import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, +) from ._typing import ( is_list_type as is_list_type, is_union_type as is_union_type, extract_type_arg as extract_type_arg, is_iterable_type as is_iterable_type, is_required_type as is_required_type, + is_sequence_type as is_sequence_type, is_annotated_type as is_annotated_type, is_type_alias_type as is_type_alias_type, strip_annotated_type as strip_annotated_type, @@ -55,3 +61,4 @@ function_has_argument as function_has_argument, assert_signatures_in_sync as assert_signatures_in_sync, ) +from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/src/asktable/_utils/_compat.py b/src/asktable/_utils/_compat.py new file mode 100644 index 00000000..2c70b299 --- /dev/null +++ b/src/asktable/_utils/_compat.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import sys +import typing_extensions +from typing import Any, Type, Union, Literal, Optional +from datetime import date, datetime +from typing_extensions import get_args as _get_args, get_origin as _get_origin + +from .._types import StrBytesIntFloat +from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime + +_LITERAL_TYPES = {Literal, typing_extensions.Literal} + + +def get_args(tp: type[Any]) -> tuple[Any, ...]: + return _get_args(tp) + + +def get_origin(tp: type[Any]) -> type[Any] | None: + return _get_origin(tp) + + +def is_union(tp: Optional[Type[Any]]) -> bool: + if sys.version_info < (3, 10): + return tp is Union # type: ignore[comparison-overlap] + else: + import types + + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] + + +def is_typeddict(tp: Type[Any]) -> bool: + return typing_extensions.is_typeddict(tp) + + +def is_literal_type(tp: Type[Any]) -> bool: + return get_origin(tp) in _LITERAL_TYPES + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + return _parse_date(value) + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + return _parse_datetime(value) diff --git a/src/asktable/_utils/_datetime_parse.py b/src/asktable/_utils/_datetime_parse.py new file mode 100644 index 00000000..7cb9d9e6 --- /dev/null +++ b/src/asktable/_utils/_datetime_parse.py @@ -0,0 +1,136 @@ +""" +This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py +without the Pydantic v1 specific errors. +""" + +from __future__ import annotations + +import re +from typing import Dict, Union, Optional +from datetime import date, datetime, timezone, timedelta + +from .._types import StrBytesIntFloat + +date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" +time_expr = ( + r"(?P\d{1,2}):(?P\d{1,2})" + r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" + r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" +) + +date_re = re.compile(f"{date_expr}$") +datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") + + +EPOCH = datetime(1970, 1, 1) +# if greater than this, the number is in ms, if less than or equal it's in seconds +# (in seconds this is 11th October 2603, in ms it's 20th August 1970) +MS_WATERSHED = int(2e10) +# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 +MAX_NUMBER = int(3e20) + + +def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: + if isinstance(value, (int, float)): + return value + try: + return float(value) + except ValueError: + return None + except TypeError: + raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None + + +def _from_unix_seconds(seconds: Union[int, float]) -> datetime: + if seconds > MAX_NUMBER: + return datetime.max + elif seconds < -MAX_NUMBER: + return datetime.min + + while abs(seconds) > MS_WATERSHED: + seconds /= 1000 + dt = EPOCH + timedelta(seconds=seconds) + return dt.replace(tzinfo=timezone.utc) + + +def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: + if value == "Z": + return timezone.utc + elif value is not None: + offset_mins = int(value[-2:]) if len(value) > 3 else 0 + offset = 60 * int(value[1:3]) + offset_mins + if value[0] == "-": + offset = -offset + return timezone(timedelta(minutes=offset)) + else: + return None + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + """ + Parse a datetime/int/float/string and return a datetime.datetime. + + This function supports time zone offsets. When the input contains one, + the output uses a timezone with a fixed offset from UTC. + + Raise ValueError if the input is well formatted but not a valid datetime. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, datetime): + return value + + number = _get_numeric(value, "datetime") + if number is not None: + return _from_unix_seconds(number) + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + + match = datetime_re.match(value) + if match is None: + raise ValueError("invalid datetime format") + + kw = match.groupdict() + if kw["microsecond"]: + kw["microsecond"] = kw["microsecond"].ljust(6, "0") + + tzinfo = _parse_timezone(kw.pop("tzinfo")) + 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 + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + """ + Parse a date/int/float/string and return a datetime.date. + + Raise ValueError if the input is well formatted but not a valid date. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, date): + if isinstance(value, datetime): + return value.date() + else: + return value + + number = _get_numeric(value, "date") + if number is not None: + return _from_unix_seconds(number).date() + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + match = date_re.match(value) + if match is None: + raise ValueError("invalid date format") + + kw = {k: int(v) for k, v in match.groupdict().items()} + + try: + return date(**kw) + except ValueError: + raise ValueError("invalid date format") from None diff --git a/src/asktable/_utils/_json.py b/src/asktable/_utils/_json.py new file mode 100644 index 00000000..60584214 --- /dev/null +++ b/src/asktable/_utils/_json.py @@ -0,0 +1,35 @@ +import json +from typing import Any +from datetime import datetime +from typing_extensions import override + +import pydantic + +from .._compat import model_dump + + +def openapi_dumps(obj: Any) -> bytes: + """ + Serialize an object to UTF-8 encoded JSON bytes. + + Extends the standard json.dumps with support for additional types + commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc. + """ + return json.dumps( + obj, + cls=_CustomEncoder, + # Uses the same defaults as httpx's JSON serialization + ensure_ascii=False, + separators=(",", ":"), + allow_nan=False, + ).encode() + + +class _CustomEncoder(json.JSONEncoder): + @override + def default(self, o: Any) -> Any: + if isinstance(o, datetime): + return o.isoformat() + if isinstance(o, pydantic.BaseModel): + return model_dump(o, exclude_unset=True, mode="json", by_alias=True) + return super().default(o) diff --git a/src/asktable/_utils/_path.py b/src/asktable/_utils/_path.py new file mode 100644 index 00000000..4d6e1e4c --- /dev/null +++ b/src/asktable/_utils/_path.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +import re +from typing import ( + Any, + Mapping, + Callable, +) +from urllib.parse import quote + +# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E). +_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$") + +_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}") + + +def _quote_path_segment_part(value: str) -> str: + """Percent-encode `value` for use in a URI path segment. + + Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 + """ + # quote() already treats unreserved characters (letters, digits, and -._~) + # as safe, so we only need to add sub-delims, ':', and '@'. + # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted. + return quote(value, safe="!$&'()*+,;=:@") + + +def _quote_query_part(value: str) -> str: + """Percent-encode `value` for use in a URI query string. + + Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.4 + """ + return quote(value, safe="!$'()*+,;:@/?") + + +def _quote_fragment_part(value: str) -> str: + """Percent-encode `value` for use in a URI fragment. + + Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.5 + """ + return quote(value, safe="!$&'()*+,;=:@/?") + + +def _interpolate( + template: str, + values: Mapping[str, Any], + quoter: Callable[[str], str], +) -> str: + """Replace {name} placeholders in `template`, quoting each value with `quoter`. + + Placeholder names are looked up in `values`. + + Raises: + KeyError: If a placeholder is not found in `values`. + """ + # re.split with a capturing group returns alternating + # [text, name, text, name, ..., text] elements. + parts = _PLACEHOLDER_RE.split(template) + + for i in range(1, len(parts), 2): + name = parts[i] + if name not in values: + raise KeyError(f"a value for placeholder {{{name}}} was not provided") + val = values[name] + if val is None: + parts[i] = "null" + elif isinstance(val, bool): + parts[i] = "true" if val else "false" + else: + parts[i] = quoter(str(values[name])) + + return "".join(parts) + + +def path_template(template: str, /, **kwargs: Any) -> str: + """Interpolate {name} placeholders in `template` from keyword arguments. + + Args: + template: The template string containing {name} placeholders. + **kwargs: Keyword arguments to interpolate into the template. + + Returns: + The template with placeholders interpolated and percent-encoded. + + Safe characters for percent-encoding are dependent on the URI component. + Placeholders in path and fragment portions are percent-encoded where the `segment` + and `fragment` sets from RFC 3986 respectively are considered safe. + Placeholders in the query portion are percent-encoded where the `query` set from + RFC 3986 §3.3 is considered safe except for = and & characters. + + Raises: + KeyError: If a placeholder is not found in `kwargs`. + ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments). + """ + # Split the template into path, query, and fragment portions. + fragment_template: str | None = None + query_template: str | None = None + + rest = template + if "#" in rest: + rest, fragment_template = rest.split("#", 1) + if "?" in rest: + rest, query_template = rest.split("?", 1) + path_template = rest + + # Interpolate each portion with the appropriate quoting rules. + path_result = _interpolate(path_template, kwargs, _quote_path_segment_part) + + # Reject dot-segments (. and ..) in the final assembled path. The check + # runs after interpolation so that adjacent placeholders or a mix of static + # text and placeholders that together form a dot-segment are caught. + # Also reject percent-encoded dot-segments to protect against incorrectly + # implemented normalization in servers/proxies. + for segment in path_result.split("/"): + if _DOT_SEGMENT_RE.match(segment): + raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed") + + result = path_result + if query_template is not None: + result += "?" + _interpolate(query_template, kwargs, _quote_query_part) + if fragment_template is not None: + result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part) + + return result diff --git a/src/asktable/_utils/_sync.py b/src/asktable/_utils/_sync.py index ad7ec71b..f6027c18 100644 --- a/src/asktable/_utils/_sync.py +++ b/src/asktable/_utils/_sync.py @@ -1,10 +1,8 @@ from __future__ import annotations -import sys import asyncio import functools -import contextvars -from typing import Any, TypeVar, Callable, Awaitable +from typing import TypeVar, Callable, Awaitable from typing_extensions import ParamSpec import anyio @@ -15,34 +13,11 @@ T_ParamSpec = ParamSpec("T_ParamSpec") -if sys.version_info >= (3, 9): - _asyncio_to_thread = asyncio.to_thread -else: - # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread - # for Python 3.8 support - async def _asyncio_to_thread( - func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs - ) -> Any: - """Asynchronously run function *func* in a separate thread. - - Any *args and **kwargs supplied for this function are directly passed - to *func*. Also, the current :class:`contextvars.Context` is propagated, - allowing context variables from the main thread to be accessed in the - separate thread. - - Returns a coroutine that can be awaited to get the eventual result of *func*. - """ - loop = asyncio.events.get_running_loop() - ctx = contextvars.copy_context() - func_call = functools.partial(ctx.run, func, *args, **kwargs) - return await loop.run_in_executor(None, func_call) - - async def to_thread( func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs ) -> T_Retval: if sniffio.current_async_library() == "asyncio": - return await _asyncio_to_thread(func, *args, **kwargs) + return await asyncio.to_thread(func, *args, **kwargs) return await anyio.to_thread.run_sync( functools.partial(func, *args, **kwargs), @@ -53,10 +28,7 @@ async def to_thread( def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: """ Take a blocking function and create an async one that receives the same - positional and keyword arguments. For python version 3.9 and above, it uses - asyncio.to_thread to run the function in a separate thread. For python version - 3.8, it uses locally defined copy of the asyncio.to_thread function which was - introduced in python 3.9. + positional and keyword arguments. Usage: diff --git a/src/asktable/_utils/_transform.py b/src/asktable/_utils/_transform.py index b0cc20a7..52075492 100644 --- a/src/asktable/_utils/_transform.py +++ b/src/asktable/_utils/_transform.py @@ -16,18 +16,20 @@ lru_cache, is_mapping, is_iterable, + is_sequence, ) from .._files import is_base64_file_input +from ._compat import get_origin, is_typeddict from ._typing import ( is_list_type, is_union_type, extract_type_arg, is_iterable_type, is_required_type, + is_sequence_type, is_annotated_type, strip_annotated_type, ) -from .._compat import get_origin, model_dump, is_typeddict _T = TypeVar("_T") @@ -167,6 +169,8 @@ def _transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation @@ -184,6 +188,8 @@ def _transform_recursive( (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) ): # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually # intended as an iterable, so we don't transform it. @@ -262,7 +268,7 @@ def _transform_typeddict( annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): if not is_given(value): - # we don't need to include `NotGiven` values here as they'll + # we don't need to include omitted values here as they'll # be stripped out before the request is sent anyway continue @@ -329,6 +335,8 @@ async def _async_transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation @@ -346,6 +354,8 @@ async def _async_transform_recursive( (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) ): # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually # intended as an iterable, so we don't transform it. @@ -424,7 +434,7 @@ async def _async_transform_typeddict( annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): if not is_given(value): - # we don't need to include `NotGiven` values here as they'll + # we don't need to include omitted values here as they'll # be stripped out before the request is sent anyway continue diff --git a/src/asktable/_utils/_typing.py b/src/asktable/_utils/_typing.py index 1bac9542..193109f3 100644 --- a/src/asktable/_utils/_typing.py +++ b/src/asktable/_utils/_typing.py @@ -15,7 +15,7 @@ from ._utils import lru_cache from .._types import InheritsGeneric -from .._compat import is_union as _is_union +from ._compat import is_union as _is_union def is_annotated_type(typ: type) -> bool: @@ -26,6 +26,11 @@ def is_list_type(typ: type) -> bool: return (get_origin(typ) or typ) == list +def is_sequence_type(typ: type) -> bool: + origin = get_origin(typ) or typ + return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence + + def is_iterable_type(typ: type) -> bool: """If the given type is `typing.Iterable[T]`""" origin = get_origin(typ) or typ diff --git a/src/asktable/_utils/_utils.py b/src/asktable/_utils/_utils.py index ea3cf3f2..199cd231 100644 --- a/src/asktable/_utils/_utils.py +++ b/src/asktable/_utils/_utils.py @@ -17,12 +17,11 @@ ) from pathlib import Path from datetime import date, datetime -from typing_extensions import TypeGuard +from typing_extensions import TypeGuard, get_args import sniffio -from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike -from .._compat import parse_date as parse_date, parse_datetime as parse_datetime +from .._types import Omit, NotGiven, FileTypes, ArrayFormat, HeadersLike _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) @@ -41,30 +40,50 @@ def extract_files( query: Mapping[str, object], *, paths: Sequence[Sequence[str]], + array_format: ArrayFormat = "brackets", ) -> list[tuple[str, FileTypes]]: """Recursively extract files from the given dictionary based on specified paths. A path may look like this ['foo', 'files', '', 'data']. + ``array_format`` controls how ```` segments contribute to the emitted + field name. Supported values: ``"brackets"`` (``foo[]``), ``"repeat"`` and + ``"comma"`` (``foo``), ``"indices"`` (``foo[0]``, ``foo[1]``). + Note: this mutates the given dictionary. """ files: list[tuple[str, FileTypes]] = [] for path in paths: - files.extend(_extract_items(query, path, index=0, flattened_key=None)) + files.extend(_extract_items(query, path, index=0, flattened_key=None, array_format=array_format)) return files +def _array_suffix(array_format: ArrayFormat, array_index: int) -> str: + if array_format == "brackets": + return "[]" + if array_format == "indices": + return f"[{array_index}]" + if array_format == "repeat" or array_format == "comma": + # Both repeat the bare field name for each file part; there is no + # meaningful way to comma-join binary parts. + return "" + raise NotImplementedError( + f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" + ) + + def _extract_items( obj: object, path: Sequence[str], *, index: int, flattened_key: str | None, + array_format: ArrayFormat, ) -> list[tuple[str, FileTypes]]: try: key = path[index] except IndexError: - if isinstance(obj, NotGiven): + if not is_given(obj): # no value was provided - we can safely ignore return [] @@ -76,9 +95,11 @@ def _extract_items( if is_list(obj): files: list[tuple[str, FileTypes]] = [] - for entry in obj: - assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "") - files.append((flattened_key + "[]", cast(FileTypes, entry))) + for array_index, entry in enumerate(obj): + suffix = _array_suffix(array_format, array_index) + emitted_key = (flattened_key + suffix) if flattened_key else suffix + assert_is_file_content(entry, key=emitted_key) + files.append((emitted_key, cast(FileTypes, entry))) return files assert_is_file_content(obj, key=flattened_key) @@ -87,8 +108,9 @@ def _extract_items( index += 1 if is_dict(obj): try: - # We are at the last entry in the path so we must remove the field - if (len(path)) == index: + # Remove the field if there are no more dict keys in the path, + # only "" traversal markers or end. + if all(p == "" for p in path[index:]): item = obj.pop(key) else: item = obj[key] @@ -106,6 +128,7 @@ def _extract_items( path, index=index, flattened_key=flattened_key, + array_format=array_format, ) elif is_list(obj): if key != "": @@ -117,9 +140,12 @@ def _extract_items( item, path, index=index, - flattened_key=flattened_key + "[]" if flattened_key is not None else "[]", + flattened_key=( + (flattened_key if flattened_key is not None else "") + _array_suffix(array_format, array_index) + ), + array_format=array_format, ) - for item in obj + for array_index, item in enumerate(obj) ] ) @@ -127,14 +153,14 @@ def _extract_items( return [] -def is_given(obj: NotGivenOr[_T]) -> TypeGuard[_T]: - return not isinstance(obj, NotGiven) +def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: + return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) # Type safe methods for narrowing types with TypeVars. # 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 it's place. +# 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 @@ -177,21 +203,6 @@ def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: return isinstance(obj, Iterable) -def deepcopy_minimal(item: _T) -> _T: - """Minimal reimplementation of copy.deepcopy() that will only copy certain object types: - - - mappings, e.g. `dict` - - list - - This is done for performance reasons. - """ - if is_mapping(item): - return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()}) - if is_list(item): - return cast(_T, [deepcopy_minimal(entry) for entry in item]) - return item - - # copied from https://github.com/Rapptz/RoboDanny def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: size = len(seq) diff --git a/src/asktable/_version.py b/src/asktable/_version.py index 118411d8..62ce948e 100644 --- a/src/asktable/_version.py +++ b/src/asktable/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "asktable" -__version__ = "5.5.0" # x-release-please-version +__version__ = "5.6.0" # x-release-please-version diff --git a/src/asktable/resources/__init__.py b/src/asktable/resources/__init__.py index 14a5d79a..7add4800 100644 --- a/src/asktable/resources/__init__.py +++ b/src/asktable/resources/__init__.py @@ -1,13 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .ats import ( - ATSResource, - AsyncATSResource, - ATSResourceWithRawResponse, - AsyncATSResourceWithRawResponse, - ATSResourceWithStreamingResponse, - AsyncATSResourceWithStreamingResponse, -) from .sys import ( SysResource, AsyncSysResource, @@ -24,22 +16,6 @@ AuthResourceWithStreamingResponse, AsyncAuthResourceWithStreamingResponse, ) -from .bots import ( - BotsResource, - AsyncBotsResource, - BotsResourceWithRawResponse, - AsyncBotsResourceWithRawResponse, - BotsResourceWithStreamingResponse, - AsyncBotsResourceWithStreamingResponse, -) -from .sqls import ( - SqlsResource, - AsyncSqlsResource, - SqlsResourceWithRawResponse, - AsyncSqlsResourceWithRawResponse, - SqlsResourceWithStreamingResponse, - AsyncSqlsResourceWithStreamingResponse, -) from .user import ( UserResource, AsyncUserResource, @@ -48,14 +24,6 @@ UserResourceWithStreamingResponse, AsyncUserResourceWithStreamingResponse, ) -from .chats import ( - ChatsResource, - AsyncChatsResource, - ChatsResourceWithRawResponse, - AsyncChatsResourceWithRawResponse, - ChatsResourceWithStreamingResponse, - AsyncChatsResourceWithStreamingResponse, -) from .files import ( FilesResource, AsyncFilesResource, @@ -64,22 +32,6 @@ FilesResourceWithStreamingResponse, AsyncFilesResourceWithStreamingResponse, ) -from .roles import ( - RolesResource, - AsyncRolesResource, - RolesResourceWithRawResponse, - AsyncRolesResourceWithRawResponse, - RolesResourceWithStreamingResponse, - AsyncRolesResourceWithStreamingResponse, -) -from .caches import ( - CachesResource, - AsyncCachesResource, - CachesResourceWithRawResponse, - AsyncCachesResourceWithRawResponse, - CachesResourceWithStreamingResponse, - AsyncCachesResourceWithStreamingResponse, -) from .polish import ( PolishResource, AsyncPolishResource, @@ -96,14 +48,6 @@ ScoresResourceWithStreamingResponse, AsyncScoresResourceWithStreamingResponse, ) -from .answers import ( - AnswersResource, - AsyncAnswersResource, - AnswersResourceWithRawResponse, - AsyncAnswersResourceWithRawResponse, - AnswersResourceWithStreamingResponse, - AsyncAnswersResourceWithStreamingResponse, -) from .project import ( ProjectResource, AsyncProjectResource, @@ -112,22 +56,6 @@ ProjectResourceWithStreamingResponse, AsyncProjectResourceWithStreamingResponse, ) -from .policies import ( - PoliciesResource, - AsyncPoliciesResource, - PoliciesResourceWithRawResponse, - AsyncPoliciesResourceWithRawResponse, - PoliciesResourceWithStreamingResponse, - AsyncPoliciesResourceWithStreamingResponse, -) -from .trainings import ( - TrainingsResource, - AsyncTrainingsResource, - TrainingsResourceWithRawResponse, - AsyncTrainingsResourceWithRawResponse, - TrainingsResourceWithStreamingResponse, - AsyncTrainingsResourceWithStreamingResponse, -) from .dataframes import ( DataframesResource, AsyncDataframesResource, @@ -152,30 +80,6 @@ IntegrationResourceWithStreamingResponse, AsyncIntegrationResourceWithStreamingResponse, ) -from .preferences import ( - PreferencesResource, - AsyncPreferencesResource, - PreferencesResourceWithRawResponse, - AsyncPreferencesResourceWithRawResponse, - PreferencesResourceWithStreamingResponse, - AsyncPreferencesResourceWithStreamingResponse, -) -from .securetunnels import ( - SecuretunnelsResource, - AsyncSecuretunnelsResource, - SecuretunnelsResourceWithRawResponse, - AsyncSecuretunnelsResourceWithRawResponse, - SecuretunnelsResourceWithStreamingResponse, - AsyncSecuretunnelsResourceWithStreamingResponse, -) -from .business_glossary import ( - BusinessGlossaryResource, - AsyncBusinessGlossaryResource, - BusinessGlossaryResourceWithRawResponse, - AsyncBusinessGlossaryResourceWithRawResponse, - BusinessGlossaryResourceWithStreamingResponse, - AsyncBusinessGlossaryResourceWithStreamingResponse, -) __all__ = [ "SysResource", @@ -184,90 +88,24 @@ "AsyncSysResourceWithRawResponse", "SysResourceWithStreamingResponse", "AsyncSysResourceWithStreamingResponse", - "SecuretunnelsResource", - "AsyncSecuretunnelsResource", - "SecuretunnelsResourceWithRawResponse", - "AsyncSecuretunnelsResourceWithRawResponse", - "SecuretunnelsResourceWithStreamingResponse", - "AsyncSecuretunnelsResourceWithStreamingResponse", - "RolesResource", - "AsyncRolesResource", - "RolesResourceWithRawResponse", - "AsyncRolesResourceWithRawResponse", - "RolesResourceWithStreamingResponse", - "AsyncRolesResourceWithStreamingResponse", - "PoliciesResource", - "AsyncPoliciesResource", - "PoliciesResourceWithRawResponse", - "AsyncPoliciesResourceWithRawResponse", - "PoliciesResourceWithStreamingResponse", - "AsyncPoliciesResourceWithStreamingResponse", - "ChatsResource", - "AsyncChatsResource", - "ChatsResourceWithRawResponse", - "AsyncChatsResourceWithRawResponse", - "ChatsResourceWithStreamingResponse", - "AsyncChatsResourceWithStreamingResponse", "DatasourcesResource", "AsyncDatasourcesResource", "DatasourcesResourceWithRawResponse", "AsyncDatasourcesResourceWithRawResponse", "DatasourcesResourceWithStreamingResponse", "AsyncDatasourcesResourceWithStreamingResponse", - "BotsResource", - "AsyncBotsResource", - "BotsResourceWithRawResponse", - "AsyncBotsResourceWithRawResponse", - "BotsResourceWithStreamingResponse", - "AsyncBotsResourceWithStreamingResponse", "AuthResource", "AsyncAuthResource", "AuthResourceWithRawResponse", "AsyncAuthResourceWithRawResponse", "AuthResourceWithStreamingResponse", "AsyncAuthResourceWithStreamingResponse", - "AnswersResource", - "AsyncAnswersResource", - "AnswersResourceWithRawResponse", - "AsyncAnswersResourceWithRawResponse", - "AnswersResourceWithStreamingResponse", - "AsyncAnswersResourceWithStreamingResponse", - "SqlsResource", - "AsyncSqlsResource", - "SqlsResourceWithRawResponse", - "AsyncSqlsResourceWithRawResponse", - "SqlsResourceWithStreamingResponse", - "AsyncSqlsResourceWithStreamingResponse", - "CachesResource", - "AsyncCachesResource", - "CachesResourceWithRawResponse", - "AsyncCachesResourceWithRawResponse", - "CachesResourceWithStreamingResponse", - "AsyncCachesResourceWithStreamingResponse", "IntegrationResource", "AsyncIntegrationResource", "IntegrationResourceWithRawResponse", "AsyncIntegrationResourceWithRawResponse", "IntegrationResourceWithStreamingResponse", "AsyncIntegrationResourceWithStreamingResponse", - "BusinessGlossaryResource", - "AsyncBusinessGlossaryResource", - "BusinessGlossaryResourceWithRawResponse", - "AsyncBusinessGlossaryResourceWithRawResponse", - "BusinessGlossaryResourceWithStreamingResponse", - "AsyncBusinessGlossaryResourceWithStreamingResponse", - "PreferencesResource", - "AsyncPreferencesResource", - "PreferencesResourceWithRawResponse", - "AsyncPreferencesResourceWithRawResponse", - "PreferencesResourceWithStreamingResponse", - "AsyncPreferencesResourceWithStreamingResponse", - "TrainingsResource", - "AsyncTrainingsResource", - "TrainingsResourceWithRawResponse", - "AsyncTrainingsResourceWithRawResponse", - "TrainingsResourceWithStreamingResponse", - "AsyncTrainingsResourceWithStreamingResponse", "ProjectResource", "AsyncProjectResource", "ProjectResourceWithRawResponse", @@ -304,10 +142,4 @@ "AsyncUserResourceWithRawResponse", "UserResourceWithStreamingResponse", "AsyncUserResourceWithStreamingResponse", - "ATSResource", - "AsyncATSResource", - "ATSResourceWithRawResponse", - "AsyncATSResourceWithRawResponse", - "ATSResourceWithStreamingResponse", - "AsyncATSResourceWithStreamingResponse", ] diff --git a/src/asktable/resources/answers.py b/src/asktable/resources/answers.py deleted file mode 100644 index 8dbd2955..00000000 --- a/src/asktable/resources/answers.py +++ /dev/null @@ -1,336 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional - -import httpx - -from ..types import answer_list_params, answer_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..pagination import SyncPage, AsyncPage -from .._base_client import AsyncPaginator, make_request_options -from ..types.answer_response import AnswerResponse - -__all__ = ["AnswersResource", "AsyncAnswersResource"] - - -class AnswersResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> AnswersResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AnswersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AnswersResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AnswersResourceWithStreamingResponse(self) - - def create( - self, - *, - datasource_id: str, - question: str, - max_rows: Optional[int] | NotGiven = NOT_GIVEN, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[object] | NotGiven = NOT_GIVEN, - with_json: Optional[bool] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AnswerResponse: - """ - 发起查询的请求 - - Args: - datasource_id: 数据源 ID - - question: 查询语句 - - max_rows: 最大返回行数,默认为 0,即不限制返回行数 - - role_id: 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - with_json: 是否同时将数据,作为 json 格式的附件一起返回 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/single-turn/q2a", - body=maybe_transform( - { - "datasource_id": datasource_id, - "question": question, - "max_rows": max_rows, - "role_id": role_id, - "role_variables": role_variables, - "with_json": with_json, - }, - answer_create_params.AnswerCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AnswerResponse, - ) - - def list( - self, - *, - datasource_id: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[AnswerResponse]: - """ - 获取所有的 Q2A 记录 - - Args: - datasource_id: 数据源 ID - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/single-turn/q2a", - page=SyncPage[AnswerResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "datasource_id": datasource_id, - "page": page, - "size": size, - }, - answer_list_params.AnswerListParams, - ), - ), - model=AnswerResponse, - ) - - -class AsyncAnswersResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncAnswersResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncAnswersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAnswersResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncAnswersResourceWithStreamingResponse(self) - - async def create( - self, - *, - datasource_id: str, - question: str, - max_rows: Optional[int] | NotGiven = NOT_GIVEN, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[object] | NotGiven = NOT_GIVEN, - with_json: Optional[bool] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AnswerResponse: - """ - 发起查询的请求 - - Args: - datasource_id: 数据源 ID - - question: 查询语句 - - max_rows: 最大返回行数,默认为 0,即不限制返回行数 - - role_id: 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - with_json: 是否同时将数据,作为 json 格式的附件一起返回 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/single-turn/q2a", - body=await async_maybe_transform( - { - "datasource_id": datasource_id, - "question": question, - "max_rows": max_rows, - "role_id": role_id, - "role_variables": role_variables, - "with_json": with_json, - }, - answer_create_params.AnswerCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AnswerResponse, - ) - - def list( - self, - *, - datasource_id: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[AnswerResponse, AsyncPage[AnswerResponse]]: - """ - 获取所有的 Q2A 记录 - - Args: - datasource_id: 数据源 ID - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/single-turn/q2a", - page=AsyncPage[AnswerResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "datasource_id": datasource_id, - "page": page, - "size": size, - }, - answer_list_params.AnswerListParams, - ), - ), - model=AnswerResponse, - ) - - -class AnswersResourceWithRawResponse: - def __init__(self, answers: AnswersResource) -> None: - self._answers = answers - - self.create = to_raw_response_wrapper( - answers.create, - ) - self.list = to_raw_response_wrapper( - answers.list, - ) - - -class AsyncAnswersResourceWithRawResponse: - def __init__(self, answers: AsyncAnswersResource) -> None: - self._answers = answers - - self.create = async_to_raw_response_wrapper( - answers.create, - ) - self.list = async_to_raw_response_wrapper( - answers.list, - ) - - -class AnswersResourceWithStreamingResponse: - def __init__(self, answers: AnswersResource) -> None: - self._answers = answers - - self.create = to_streamed_response_wrapper( - answers.create, - ) - self.list = to_streamed_response_wrapper( - answers.list, - ) - - -class AsyncAnswersResourceWithStreamingResponse: - def __init__(self, answers: AsyncAnswersResource) -> None: - self._answers = answers - - self.create = async_to_streamed_response_wrapper( - answers.create, - ) - self.list = async_to_streamed_response_wrapper( - answers.list, - ) diff --git a/src/asktable/resources/ats/__init__.py b/src/asktable/resources/ats/__init__.py deleted file mode 100644 index 698c217d..00000000 --- a/src/asktable/resources/ats/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .ats import ( - ATSResource, - AsyncATSResource, - ATSResourceWithRawResponse, - AsyncATSResourceWithRawResponse, - ATSResourceWithStreamingResponse, - AsyncATSResourceWithStreamingResponse, -) -from .task import ( - TaskResource, - AsyncTaskResource, - TaskResourceWithRawResponse, - AsyncTaskResourceWithRawResponse, - TaskResourceWithStreamingResponse, - AsyncTaskResourceWithStreamingResponse, -) -from .test_case import ( - TestCaseResource, - AsyncTestCaseResource, - TestCaseResourceWithRawResponse, - AsyncTestCaseResourceWithRawResponse, - TestCaseResourceWithStreamingResponse, - AsyncTestCaseResourceWithStreamingResponse, -) - -__all__ = [ - "TestCaseResource", - "AsyncTestCaseResource", - "TestCaseResourceWithRawResponse", - "AsyncTestCaseResourceWithRawResponse", - "TestCaseResourceWithStreamingResponse", - "AsyncTestCaseResourceWithStreamingResponse", - "TaskResource", - "AsyncTaskResource", - "TaskResourceWithRawResponse", - "AsyncTaskResourceWithRawResponse", - "TaskResourceWithStreamingResponse", - "AsyncTaskResourceWithStreamingResponse", - "ATSResource", - "AsyncATSResource", - "ATSResourceWithRawResponse", - "AsyncATSResourceWithRawResponse", - "ATSResourceWithStreamingResponse", - "AsyncATSResourceWithStreamingResponse", -] diff --git a/src/asktable/resources/ats/ats.py b/src/asktable/resources/ats/ats.py deleted file mode 100644 index 64276c0d..00000000 --- a/src/asktable/resources/ats/ats.py +++ /dev/null @@ -1,623 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .task import ( - TaskResource, - AsyncTaskResource, - TaskResourceWithRawResponse, - AsyncTaskResourceWithRawResponse, - TaskResourceWithStreamingResponse, - AsyncTaskResourceWithStreamingResponse, -) -from ...types import ats_list_params, ats_create_params, ats_delete_params, ats_update_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from .test_case import ( - TestCaseResource, - AsyncTestCaseResource, - TestCaseResourceWithRawResponse, - AsyncTestCaseResourceWithRawResponse, - TestCaseResourceWithStreamingResponse, - AsyncTestCaseResourceWithStreamingResponse, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncPage, AsyncPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.ats_list_response import ATSListResponse -from ...types.ats_create_response import ATSCreateResponse -from ...types.ats_update_response import ATSUpdateResponse -from ...types.ats_retrieve_response import ATSRetrieveResponse - -__all__ = ["ATSResource", "AsyncATSResource"] - - -class ATSResource(SyncAPIResource): - @cached_property - def test_case(self) -> TestCaseResource: - return TestCaseResource(self._client) - - @cached_property - def task(self) -> TaskResource: - return TaskResource(self._client) - - @cached_property - def with_raw_response(self) -> ATSResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return ATSResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ATSResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return ATSResourceWithStreamingResponse(self) - - def create( - self, - *, - datasource_id: str, - name: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ATSCreateResponse: - """ - Create Test Set Endpoint - - Args: - datasource_id: 该测试集对应数据源的 ID - - name: 测试集名称 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/ats", - body=maybe_transform( - { - "datasource_id": datasource_id, - "name": name, - }, - ats_create_params.ATSCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ATSCreateResponse, - ) - - def retrieve( - self, - ats_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ATSRetrieveResponse: - """ - Get Test Set Endpoint - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._get( - f"/v1/ats/{ats_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ATSRetrieveResponse, - ) - - def update( - self, - ats_id: str, - *, - name: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ATSUpdateResponse: - """ - Update Test Set Endpoint - - Args: - name: 测试集更新的名字 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._patch( - f"/v1/ats/{ats_id}", - body=maybe_transform({"name": name}, ats_update_params.ATSUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ATSUpdateResponse, - ) - - def list( - self, - *, - datasource_id: str, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[ATSListResponse]: - """ - Get Test Sets Endpoint - - Args: - datasource_id: 数据源 ID - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/ats", - page=SyncPage[ATSListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "datasource_id": datasource_id, - "page": page, - "size": size, - }, - ats_list_params.ATSListParams, - ), - ), - model=ATSListResponse, - ) - - def delete( - self, - ats_id: str, - *, - datasource_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - Delete Test Set Endpoint - - Args: - datasource_id: 数据源 ID - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._delete( - f"/v1/ats/{ats_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"datasource_id": datasource_id}, ats_delete_params.ATSDeleteParams), - ), - cast_to=object, - ) - - -class AsyncATSResource(AsyncAPIResource): - @cached_property - def test_case(self) -> AsyncTestCaseResource: - return AsyncTestCaseResource(self._client) - - @cached_property - def task(self) -> AsyncTaskResource: - return AsyncTaskResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncATSResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncATSResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncATSResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncATSResourceWithStreamingResponse(self) - - async def create( - self, - *, - datasource_id: str, - name: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ATSCreateResponse: - """ - Create Test Set Endpoint - - Args: - datasource_id: 该测试集对应数据源的 ID - - name: 测试集名称 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/ats", - body=await async_maybe_transform( - { - "datasource_id": datasource_id, - "name": name, - }, - ats_create_params.ATSCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ATSCreateResponse, - ) - - async def retrieve( - self, - ats_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ATSRetrieveResponse: - """ - Get Test Set Endpoint - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return await self._get( - f"/v1/ats/{ats_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ATSRetrieveResponse, - ) - - async def update( - self, - ats_id: str, - *, - name: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ATSUpdateResponse: - """ - Update Test Set Endpoint - - Args: - name: 测试集更新的名字 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return await self._patch( - f"/v1/ats/{ats_id}", - body=await async_maybe_transform({"name": name}, ats_update_params.ATSUpdateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ATSUpdateResponse, - ) - - def list( - self, - *, - datasource_id: str, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[ATSListResponse, AsyncPage[ATSListResponse]]: - """ - Get Test Sets Endpoint - - Args: - datasource_id: 数据源 ID - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/ats", - page=AsyncPage[ATSListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "datasource_id": datasource_id, - "page": page, - "size": size, - }, - ats_list_params.ATSListParams, - ), - ), - model=ATSListResponse, - ) - - async def delete( - self, - ats_id: str, - *, - datasource_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - Delete Test Set Endpoint - - Args: - datasource_id: 数据源 ID - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return await self._delete( - f"/v1/ats/{ats_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"datasource_id": datasource_id}, ats_delete_params.ATSDeleteParams), - ), - cast_to=object, - ) - - -class ATSResourceWithRawResponse: - def __init__(self, ats: ATSResource) -> None: - self._ats = ats - - self.create = to_raw_response_wrapper( - ats.create, - ) - self.retrieve = to_raw_response_wrapper( - ats.retrieve, - ) - self.update = to_raw_response_wrapper( - ats.update, - ) - self.list = to_raw_response_wrapper( - ats.list, - ) - self.delete = to_raw_response_wrapper( - ats.delete, - ) - - @cached_property - def test_case(self) -> TestCaseResourceWithRawResponse: - return TestCaseResourceWithRawResponse(self._ats.test_case) - - @cached_property - def task(self) -> TaskResourceWithRawResponse: - return TaskResourceWithRawResponse(self._ats.task) - - -class AsyncATSResourceWithRawResponse: - def __init__(self, ats: AsyncATSResource) -> None: - self._ats = ats - - self.create = async_to_raw_response_wrapper( - ats.create, - ) - self.retrieve = async_to_raw_response_wrapper( - ats.retrieve, - ) - self.update = async_to_raw_response_wrapper( - ats.update, - ) - self.list = async_to_raw_response_wrapper( - ats.list, - ) - self.delete = async_to_raw_response_wrapper( - ats.delete, - ) - - @cached_property - def test_case(self) -> AsyncTestCaseResourceWithRawResponse: - return AsyncTestCaseResourceWithRawResponse(self._ats.test_case) - - @cached_property - def task(self) -> AsyncTaskResourceWithRawResponse: - return AsyncTaskResourceWithRawResponse(self._ats.task) - - -class ATSResourceWithStreamingResponse: - def __init__(self, ats: ATSResource) -> None: - self._ats = ats - - self.create = to_streamed_response_wrapper( - ats.create, - ) - self.retrieve = to_streamed_response_wrapper( - ats.retrieve, - ) - self.update = to_streamed_response_wrapper( - ats.update, - ) - self.list = to_streamed_response_wrapper( - ats.list, - ) - self.delete = to_streamed_response_wrapper( - ats.delete, - ) - - @cached_property - def test_case(self) -> TestCaseResourceWithStreamingResponse: - return TestCaseResourceWithStreamingResponse(self._ats.test_case) - - @cached_property - def task(self) -> TaskResourceWithStreamingResponse: - return TaskResourceWithStreamingResponse(self._ats.task) - - -class AsyncATSResourceWithStreamingResponse: - def __init__(self, ats: AsyncATSResource) -> None: - self._ats = ats - - self.create = async_to_streamed_response_wrapper( - ats.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - ats.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - ats.update, - ) - self.list = async_to_streamed_response_wrapper( - ats.list, - ) - self.delete = async_to_streamed_response_wrapper( - ats.delete, - ) - - @cached_property - def test_case(self) -> AsyncTestCaseResourceWithStreamingResponse: - return AsyncTestCaseResourceWithStreamingResponse(self._ats.test_case) - - @cached_property - def task(self) -> AsyncTaskResourceWithStreamingResponse: - return AsyncTaskResourceWithStreamingResponse(self._ats.task) diff --git a/src/asktable/resources/ats/task.py b/src/asktable/resources/ats/task.py deleted file mode 100644 index 7950fed9..00000000 --- a/src/asktable/resources/ats/task.py +++ /dev/null @@ -1,509 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List - -import httpx - -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...types.ats import task_run_params, task_list_params, task_get_case_tasks_params -from ...pagination import SyncPage, AsyncPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.ats.task_run_response import TaskRunResponse -from ...types.ats.task_list_response import TaskListResponse -from ...types.ats.task_retrieve_response import TaskRetrieveResponse -from ...types.ats.task_get_case_tasks_response import TaskGetCaseTasksResponse - -__all__ = ["TaskResource", "AsyncTaskResource"] - - -class TaskResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> TaskResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return TaskResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TaskResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return TaskResourceWithStreamingResponse(self) - - def retrieve( - self, - ats_task_id: str, - *, - ats_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TaskRetrieveResponse: - """ - Get Test Task Endpoint - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not ats_task_id: - raise ValueError(f"Expected a non-empty value for `ats_task_id` but received {ats_task_id!r}") - return self._get( - f"/v1/ats/{ats_id}/task/{ats_task_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TaskRetrieveResponse, - ) - - def list( - self, - ats_id: str, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[TaskListResponse]: - """ - Get Test Tasks Endpoint - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._get_api_list( - f"/v1/ats/{ats_id}/task", - page=SyncPage[TaskListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - task_list_params.TaskListParams, - ), - ), - model=TaskListResponse, - ) - - def get_case_tasks( - self, - ats_task_id: str, - *, - ats_id: str, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TaskGetCaseTasksResponse: - """ - Get Test Case Tasks Endpoint - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not ats_task_id: - raise ValueError(f"Expected a non-empty value for `ats_task_id` but received {ats_task_id!r}") - return self._get( - f"/v1/ats/{ats_id}/task/{ats_task_id}/case", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - task_get_case_tasks_params.TaskGetCaseTasksParams, - ), - ), - cast_to=TaskGetCaseTasksResponse, - ) - - def run( - self, - ats_id: str, - *, - datasource_id: str, - specific_case_ids: List[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TaskRunResponse: - """ - Run Task Endpoint - - Args: - datasource_id: 数据源 ID - - specific_case_ids: 测试用例 ID 列表 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._post( - f"/v1/ats/{ats_id}/task", - body=maybe_transform( - { - "datasource_id": datasource_id, - "specific_case_ids": specific_case_ids, - }, - task_run_params.TaskRunParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TaskRunResponse, - ) - - -class AsyncTaskResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncTaskResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncTaskResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTaskResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncTaskResourceWithStreamingResponse(self) - - async def retrieve( - self, - ats_task_id: str, - *, - ats_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TaskRetrieveResponse: - """ - Get Test Task Endpoint - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not ats_task_id: - raise ValueError(f"Expected a non-empty value for `ats_task_id` but received {ats_task_id!r}") - return await self._get( - f"/v1/ats/{ats_id}/task/{ats_task_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TaskRetrieveResponse, - ) - - def list( - self, - ats_id: str, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[TaskListResponse, AsyncPage[TaskListResponse]]: - """ - Get Test Tasks Endpoint - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._get_api_list( - f"/v1/ats/{ats_id}/task", - page=AsyncPage[TaskListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - task_list_params.TaskListParams, - ), - ), - model=TaskListResponse, - ) - - async def get_case_tasks( - self, - ats_task_id: str, - *, - ats_id: str, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TaskGetCaseTasksResponse: - """ - Get Test Case Tasks Endpoint - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not ats_task_id: - raise ValueError(f"Expected a non-empty value for `ats_task_id` but received {ats_task_id!r}") - return await self._get( - f"/v1/ats/{ats_id}/task/{ats_task_id}/case", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "page": page, - "size": size, - }, - task_get_case_tasks_params.TaskGetCaseTasksParams, - ), - ), - cast_to=TaskGetCaseTasksResponse, - ) - - async def run( - self, - ats_id: str, - *, - datasource_id: str, - specific_case_ids: List[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TaskRunResponse: - """ - Run Task Endpoint - - Args: - datasource_id: 数据源 ID - - specific_case_ids: 测试用例 ID 列表 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return await self._post( - f"/v1/ats/{ats_id}/task", - body=await async_maybe_transform( - { - "datasource_id": datasource_id, - "specific_case_ids": specific_case_ids, - }, - task_run_params.TaskRunParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TaskRunResponse, - ) - - -class TaskResourceWithRawResponse: - def __init__(self, task: TaskResource) -> None: - self._task = task - - self.retrieve = to_raw_response_wrapper( - task.retrieve, - ) - self.list = to_raw_response_wrapper( - task.list, - ) - self.get_case_tasks = to_raw_response_wrapper( - task.get_case_tasks, - ) - self.run = to_raw_response_wrapper( - task.run, - ) - - -class AsyncTaskResourceWithRawResponse: - def __init__(self, task: AsyncTaskResource) -> None: - self._task = task - - self.retrieve = async_to_raw_response_wrapper( - task.retrieve, - ) - self.list = async_to_raw_response_wrapper( - task.list, - ) - self.get_case_tasks = async_to_raw_response_wrapper( - task.get_case_tasks, - ) - self.run = async_to_raw_response_wrapper( - task.run, - ) - - -class TaskResourceWithStreamingResponse: - def __init__(self, task: TaskResource) -> None: - self._task = task - - self.retrieve = to_streamed_response_wrapper( - task.retrieve, - ) - self.list = to_streamed_response_wrapper( - task.list, - ) - self.get_case_tasks = to_streamed_response_wrapper( - task.get_case_tasks, - ) - self.run = to_streamed_response_wrapper( - task.run, - ) - - -class AsyncTaskResourceWithStreamingResponse: - def __init__(self, task: AsyncTaskResource) -> None: - self._task = task - - self.retrieve = async_to_streamed_response_wrapper( - task.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - task.list, - ) - self.get_case_tasks = async_to_streamed_response_wrapper( - task.get_case_tasks, - ) - self.run = async_to_streamed_response_wrapper( - task.run, - ) diff --git a/src/asktable/resources/ats/test_case.py b/src/asktable/resources/ats/test_case.py deleted file mode 100644 index 58852a1a..00000000 --- a/src/asktable/resources/ats/test_case.py +++ /dev/null @@ -1,625 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional - -import httpx - -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...types.ats import test_case_list_params, test_case_create_params, test_case_update_params -from ...pagination import SyncPage, AsyncPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.ats.test_case_list_response import TestCaseListResponse -from ...types.ats.test_case_create_response import TestCaseCreateResponse -from ...types.ats.test_case_update_response import TestCaseUpdateResponse -from ...types.ats.test_case_retrieve_response import TestCaseRetrieveResponse - -__all__ = ["TestCaseResource", "AsyncTestCaseResource"] - - -class TestCaseResource(SyncAPIResource): - __test__ = False - - @cached_property - def with_raw_response(self) -> TestCaseResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return TestCaseResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TestCaseResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return TestCaseResourceWithStreamingResponse(self) - - def create( - self, - ats_id: str, - *, - expected_sql: str, - question: str, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[object] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TestCaseCreateResponse: - """ - Create Test Case Endpoint - - Args: - expected_sql: 用户期望生成的 sql - - question: 用户提问 - - role_id: 角色 ID - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._post( - f"/v1/ats/{ats_id}/test-case", - body=maybe_transform( - { - "expected_sql": expected_sql, - "question": question, - "role_id": role_id, - "role_variables": role_variables, - }, - test_case_create_params.TestCaseCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TestCaseCreateResponse, - ) - - def retrieve( - self, - atc_id: str, - *, - ats_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TestCaseRetrieveResponse: - """ - Get Test Case Endpoint - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not atc_id: - raise ValueError(f"Expected a non-empty value for `atc_id` but received {atc_id!r}") - return self._get( - f"/v1/ats/{ats_id}/test-case/{atc_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TestCaseRetrieveResponse, - ) - - def update( - self, - atc_id: str, - *, - ats_id: str, - expected_sql: str, - question: str, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[object] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TestCaseUpdateResponse: - """ - Update Test Case Endpoint - - Args: - expected_sql: 用户期望生成的 sql - - question: 用户提问 - - role_id: 角色 ID - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not atc_id: - raise ValueError(f"Expected a non-empty value for `atc_id` but received {atc_id!r}") - return self._patch( - f"/v1/ats/{ats_id}/test-case/{atc_id}", - body=maybe_transform( - { - "expected_sql": expected_sql, - "question": question, - "role_id": role_id, - "role_variables": role_variables, - }, - test_case_update_params.TestCaseUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TestCaseUpdateResponse, - ) - - def list( - self, - ats_id: str, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[TestCaseListResponse]: - """ - Get Test Cases Endpoint - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._get_api_list( - f"/v1/ats/{ats_id}/test-case", - page=SyncPage[TestCaseListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - test_case_list_params.TestCaseListParams, - ), - ), - model=TestCaseListResponse, - ) - - def delete( - self, - atc_id: str, - *, - ats_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - Delete Test Case Endpoint - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not atc_id: - raise ValueError(f"Expected a non-empty value for `atc_id` but received {atc_id!r}") - return self._delete( - f"/v1/ats/{ats_id}/test-case/{atc_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - -class AsyncTestCaseResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncTestCaseResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncTestCaseResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTestCaseResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncTestCaseResourceWithStreamingResponse(self) - - async def create( - self, - ats_id: str, - *, - expected_sql: str, - question: str, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[object] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TestCaseCreateResponse: - """ - Create Test Case Endpoint - - Args: - expected_sql: 用户期望生成的 sql - - question: 用户提问 - - role_id: 角色 ID - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return await self._post( - f"/v1/ats/{ats_id}/test-case", - body=await async_maybe_transform( - { - "expected_sql": expected_sql, - "question": question, - "role_id": role_id, - "role_variables": role_variables, - }, - test_case_create_params.TestCaseCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TestCaseCreateResponse, - ) - - async def retrieve( - self, - atc_id: str, - *, - ats_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TestCaseRetrieveResponse: - """ - Get Test Case Endpoint - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not atc_id: - raise ValueError(f"Expected a non-empty value for `atc_id` but received {atc_id!r}") - return await self._get( - f"/v1/ats/{ats_id}/test-case/{atc_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TestCaseRetrieveResponse, - ) - - async def update( - self, - atc_id: str, - *, - ats_id: str, - expected_sql: str, - question: str, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[object] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TestCaseUpdateResponse: - """ - Update Test Case Endpoint - - Args: - expected_sql: 用户期望生成的 sql - - question: 用户提问 - - role_id: 角色 ID - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not atc_id: - raise ValueError(f"Expected a non-empty value for `atc_id` but received {atc_id!r}") - return await self._patch( - f"/v1/ats/{ats_id}/test-case/{atc_id}", - body=await async_maybe_transform( - { - "expected_sql": expected_sql, - "question": question, - "role_id": role_id, - "role_variables": role_variables, - }, - test_case_update_params.TestCaseUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=TestCaseUpdateResponse, - ) - - def list( - self, - ats_id: str, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[TestCaseListResponse, AsyncPage[TestCaseListResponse]]: - """ - Get Test Cases Endpoint - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - return self._get_api_list( - f"/v1/ats/{ats_id}/test-case", - page=AsyncPage[TestCaseListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - test_case_list_params.TestCaseListParams, - ), - ), - model=TestCaseListResponse, - ) - - async def delete( - self, - atc_id: str, - *, - ats_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - Delete Test Case Endpoint - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not ats_id: - raise ValueError(f"Expected a non-empty value for `ats_id` but received {ats_id!r}") - if not atc_id: - raise ValueError(f"Expected a non-empty value for `atc_id` but received {atc_id!r}") - return await self._delete( - f"/v1/ats/{ats_id}/test-case/{atc_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - -class TestCaseResourceWithRawResponse: - __test__ = False - - def __init__(self, test_case: TestCaseResource) -> None: - self._test_case = test_case - - self.create = to_raw_response_wrapper( - test_case.create, - ) - self.retrieve = to_raw_response_wrapper( - test_case.retrieve, - ) - self.update = to_raw_response_wrapper( - test_case.update, - ) - self.list = to_raw_response_wrapper( - test_case.list, - ) - self.delete = to_raw_response_wrapper( - test_case.delete, - ) - - -class AsyncTestCaseResourceWithRawResponse: - def __init__(self, test_case: AsyncTestCaseResource) -> None: - self._test_case = test_case - - self.create = async_to_raw_response_wrapper( - test_case.create, - ) - self.retrieve = async_to_raw_response_wrapper( - test_case.retrieve, - ) - self.update = async_to_raw_response_wrapper( - test_case.update, - ) - self.list = async_to_raw_response_wrapper( - test_case.list, - ) - self.delete = async_to_raw_response_wrapper( - test_case.delete, - ) - - -class TestCaseResourceWithStreamingResponse: - __test__ = False - - def __init__(self, test_case: TestCaseResource) -> None: - self._test_case = test_case - - self.create = to_streamed_response_wrapper( - test_case.create, - ) - self.retrieve = to_streamed_response_wrapper( - test_case.retrieve, - ) - self.update = to_streamed_response_wrapper( - test_case.update, - ) - self.list = to_streamed_response_wrapper( - test_case.list, - ) - self.delete = to_streamed_response_wrapper( - test_case.delete, - ) - - -class AsyncTestCaseResourceWithStreamingResponse: - def __init__(self, test_case: AsyncTestCaseResource) -> None: - self._test_case = test_case - - self.create = async_to_streamed_response_wrapper( - test_case.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - test_case.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - test_case.update, - ) - self.list = async_to_streamed_response_wrapper( - test_case.list, - ) - self.delete = async_to_streamed_response_wrapper( - test_case.delete, - ) diff --git a/src/asktable/resources/auth.py b/src/asktable/resources/auth.py index 065e06f1..8594fb2e 100644 --- a/src/asktable/resources/auth.py +++ b/src/asktable/resources/auth.py @@ -2,13 +2,13 @@ from __future__ import annotations -from typing import Optional +from typing import Dict, Optional from typing_extensions import Literal import httpx from ..types import auth_create_token_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -20,11 +20,14 @@ ) from .._base_client import make_request_options from ..types.auth_me_response import AuthMeResponse +from ..types.auth_create_token_response import AuthCreateTokenResponse __all__ = ["AuthResource", "AsyncAuthResource"] class AuthResource(SyncAPIResource): + """AskTable 系统认证管理""" + @cached_property def with_raw_response(self) -> AuthResourceWithRawResponse: """ @@ -47,17 +50,17 @@ def with_streaming_response(self) -> AuthResourceWithStreamingResponse: def create_token( self, *, - ak_role: Literal["sys", "admin", "asker", "visitor"] | NotGiven = NOT_GIVEN, - chat_role: Optional[auth_create_token_params.ChatRole] | NotGiven = NOT_GIVEN, - token_ttl: int | NotGiven = NOT_GIVEN, - user_profile: Optional[object] | NotGiven = NOT_GIVEN, + ak_role: Literal["sys", "admin", "asker"] | Omit = omit, + chat_role: Optional[auth_create_token_params.ChatRole] | Omit = omit, + token_ttl: int | Omit = omit, + user_profile: Optional[Dict[str, object]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AuthCreateTokenResponse: """ Create Token @@ -92,7 +95,7 @@ def create_token( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=AuthCreateTokenResponse, ) def me( @@ -103,7 +106,7 @@ def me( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuthMeResponse: """获取当前登录的 TokenID""" return self._get( @@ -116,6 +119,8 @@ def me( class AsyncAuthResource(AsyncAPIResource): + """AskTable 系统认证管理""" + @cached_property def with_raw_response(self) -> AsyncAuthResourceWithRawResponse: """ @@ -138,17 +143,17 @@ def with_streaming_response(self) -> AsyncAuthResourceWithStreamingResponse: async def create_token( self, *, - ak_role: Literal["sys", "admin", "asker", "visitor"] | NotGiven = NOT_GIVEN, - chat_role: Optional[auth_create_token_params.ChatRole] | NotGiven = NOT_GIVEN, - token_ttl: int | NotGiven = NOT_GIVEN, - user_profile: Optional[object] | NotGiven = NOT_GIVEN, + ak_role: Literal["sys", "admin", "asker"] | Omit = omit, + chat_role: Optional[auth_create_token_params.ChatRole] | Omit = omit, + token_ttl: int | Omit = omit, + user_profile: Optional[Dict[str, object]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AuthCreateTokenResponse: """ Create Token @@ -183,7 +188,7 @@ async def create_token( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=AuthCreateTokenResponse, ) async def me( @@ -194,7 +199,7 @@ async def me( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuthMeResponse: """获取当前登录的 TokenID""" return await self._get( diff --git a/src/asktable/resources/bots.py b/src/asktable/resources/bots.py deleted file mode 100644 index a64fb2d0..00000000 --- a/src/asktable/resources/bots.py +++ /dev/null @@ -1,842 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Iterable, Optional - -import httpx - -from ..types import bot_list_params, bot_create_params, bot_invite_params, bot_update_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..pagination import SyncPage, AsyncPage -from .._base_client import AsyncPaginator, make_request_options -from ..types.chatbot import Chatbot - -__all__ = ["BotsResource", "AsyncBotsResource"] - - -class BotsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> BotsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return BotsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> BotsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return BotsResourceWithStreamingResponse(self) - - def create( - self, - *, - datasource_ids: List[str], - name: str, - color_theme: Optional[str] | NotGiven = NOT_GIVEN, - debug: bool | NotGiven = NOT_GIVEN, - extapi_ids: List[str] | NotGiven = NOT_GIVEN, - interaction_rules: Iterable[bot_create_params.InteractionRule] | NotGiven = NOT_GIVEN, - magic_input: Optional[str] | NotGiven = NOT_GIVEN, - max_rows: int | NotGiven = NOT_GIVEN, - publish: bool | NotGiven = NOT_GIVEN, - query_balance: Optional[int] | NotGiven = NOT_GIVEN, - sample_questions: Optional[List[str]] | NotGiven = NOT_GIVEN, - webhooks: List[str] | NotGiven = NOT_GIVEN, - welcome_message: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Chatbot: - """ - 创建一个新的 Bot - - Args: - datasource_ids: 数据源 ID,目前只支持 1 个数据源。 - - name: 名称,不超过 64 个字符 - - color_theme: 颜色主题 - - debug: 调试模式 - - extapi_ids: 扩展 API ID 列表,扩展 API ID 的逗号分隔列表。 - - interaction_rules: 交互规则列表,用于定义 bot 的行为规则 - - magic_input: 魔法提示词 - - max_rows: 最大返回行数,默认不限制 - - publish: 是否公开 - - query_balance: bot 的查询次数,默认是 None,表示无限次查询,入参为大于等于 0 的整数 - - sample_questions: 示例问题列表 - - webhooks: Webhook URL 列表 - - welcome_message: 欢迎消息 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/bots", - body=maybe_transform( - { - "datasource_ids": datasource_ids, - "name": name, - "color_theme": color_theme, - "debug": debug, - "extapi_ids": extapi_ids, - "interaction_rules": interaction_rules, - "magic_input": magic_input, - "max_rows": max_rows, - "publish": publish, - "query_balance": query_balance, - "sample_questions": sample_questions, - "webhooks": webhooks, - "welcome_message": welcome_message, - }, - bot_create_params.BotCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Chatbot, - ) - - def retrieve( - self, - bot_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Chatbot: - """ - 获取某个 Bot - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not bot_id: - raise ValueError(f"Expected a non-empty value for `bot_id` but received {bot_id!r}") - return self._get( - f"/v1/bots/{bot_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Chatbot, - ) - - def update( - self, - bot_id: str, - *, - avatar_url: Optional[str] | NotGiven = NOT_GIVEN, - color_theme: Optional[str] | NotGiven = NOT_GIVEN, - datasource_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - debug: Optional[bool] | NotGiven = NOT_GIVEN, - extapi_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - interaction_rules: Optional[Iterable[bot_update_params.InteractionRule]] | NotGiven = NOT_GIVEN, - magic_input: Optional[str] | NotGiven = NOT_GIVEN, - max_rows: Optional[int] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - publish: Optional[bool] | NotGiven = NOT_GIVEN, - query_balance: Optional[int] | NotGiven = NOT_GIVEN, - sample_questions: Optional[List[str]] | NotGiven = NOT_GIVEN, - webhooks: Optional[List[str]] | NotGiven = NOT_GIVEN, - welcome_message: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Chatbot: - """ - 更新某个 Bot - - Args: - avatar_url: 头像 URL - - color_theme: 颜色主题 - - datasource_ids: 数据源 ID,目前只支持 1 个数据源。 - - debug: 调试模式 - - extapi_ids: 扩展 API ID 列表,扩展 API ID 的逗号分隔列表。 - - interaction_rules: 交互规则列表,用于定义 bot 的行为规则 - - magic_input: 魔法提示词 - - max_rows: 最大返回行数,默认不限制 - - name: 名称,不超过 64 个字符 - - publish: 是否公开 - - query_balance: bot 的查询次数,默认是 None,表示无限次查询,入参为大于等于 0 的整数 - - sample_questions: 示例问题列表 - - webhooks: Webhook URL 列表 - - welcome_message: 欢迎消息 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not bot_id: - raise ValueError(f"Expected a non-empty value for `bot_id` but received {bot_id!r}") - return self._patch( - f"/v1/bots/{bot_id}", - body=maybe_transform( - { - "avatar_url": avatar_url, - "color_theme": color_theme, - "datasource_ids": datasource_ids, - "debug": debug, - "extapi_ids": extapi_ids, - "interaction_rules": interaction_rules, - "magic_input": magic_input, - "max_rows": max_rows, - "name": name, - "publish": publish, - "query_balance": query_balance, - "sample_questions": sample_questions, - "webhooks": webhooks, - "welcome_message": welcome_message, - }, - bot_update_params.BotUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Chatbot, - ) - - def list( - self, - *, - bot_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[Chatbot]: - """ - 查询所有 Bot - - Args: - bot_ids: Bot ID - - name: 名称 - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/bots", - page=SyncPage[Chatbot], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "bot_ids": bot_ids, - "name": name, - "page": page, - "size": size, - }, - bot_list_params.BotListParams, - ), - ), - model=Chatbot, - ) - - def delete( - self, - bot_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 删除某个 Bot - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not bot_id: - raise ValueError(f"Expected a non-empty value for `bot_id` but received {bot_id!r}") - return self._delete( - f"/v1/bots/{bot_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - def invite( - self, - bot_id: str, - *, - project_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 邀请用户加入对话 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not bot_id: - raise ValueError(f"Expected a non-empty value for `bot_id` but received {bot_id!r}") - return self._post( - f"/v1/bots/{bot_id}/invite", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"project_id": project_id}, bot_invite_params.BotInviteParams), - ), - cast_to=object, - ) - - -class AsyncBotsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncBotsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncBotsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncBotsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncBotsResourceWithStreamingResponse(self) - - async def create( - self, - *, - datasource_ids: List[str], - name: str, - color_theme: Optional[str] | NotGiven = NOT_GIVEN, - debug: bool | NotGiven = NOT_GIVEN, - extapi_ids: List[str] | NotGiven = NOT_GIVEN, - interaction_rules: Iterable[bot_create_params.InteractionRule] | NotGiven = NOT_GIVEN, - magic_input: Optional[str] | NotGiven = NOT_GIVEN, - max_rows: int | NotGiven = NOT_GIVEN, - publish: bool | NotGiven = NOT_GIVEN, - query_balance: Optional[int] | NotGiven = NOT_GIVEN, - sample_questions: Optional[List[str]] | NotGiven = NOT_GIVEN, - webhooks: List[str] | NotGiven = NOT_GIVEN, - welcome_message: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Chatbot: - """ - 创建一个新的 Bot - - Args: - datasource_ids: 数据源 ID,目前只支持 1 个数据源。 - - name: 名称,不超过 64 个字符 - - color_theme: 颜色主题 - - debug: 调试模式 - - extapi_ids: 扩展 API ID 列表,扩展 API ID 的逗号分隔列表。 - - interaction_rules: 交互规则列表,用于定义 bot 的行为规则 - - magic_input: 魔法提示词 - - max_rows: 最大返回行数,默认不限制 - - publish: 是否公开 - - query_balance: bot 的查询次数,默认是 None,表示无限次查询,入参为大于等于 0 的整数 - - sample_questions: 示例问题列表 - - webhooks: Webhook URL 列表 - - welcome_message: 欢迎消息 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/bots", - body=await async_maybe_transform( - { - "datasource_ids": datasource_ids, - "name": name, - "color_theme": color_theme, - "debug": debug, - "extapi_ids": extapi_ids, - "interaction_rules": interaction_rules, - "magic_input": magic_input, - "max_rows": max_rows, - "publish": publish, - "query_balance": query_balance, - "sample_questions": sample_questions, - "webhooks": webhooks, - "welcome_message": welcome_message, - }, - bot_create_params.BotCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Chatbot, - ) - - async def retrieve( - self, - bot_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Chatbot: - """ - 获取某个 Bot - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not bot_id: - raise ValueError(f"Expected a non-empty value for `bot_id` but received {bot_id!r}") - return await self._get( - f"/v1/bots/{bot_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Chatbot, - ) - - async def update( - self, - bot_id: str, - *, - avatar_url: Optional[str] | NotGiven = NOT_GIVEN, - color_theme: Optional[str] | NotGiven = NOT_GIVEN, - datasource_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - debug: Optional[bool] | NotGiven = NOT_GIVEN, - extapi_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - interaction_rules: Optional[Iterable[bot_update_params.InteractionRule]] | NotGiven = NOT_GIVEN, - magic_input: Optional[str] | NotGiven = NOT_GIVEN, - max_rows: Optional[int] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - publish: Optional[bool] | NotGiven = NOT_GIVEN, - query_balance: Optional[int] | NotGiven = NOT_GIVEN, - sample_questions: Optional[List[str]] | NotGiven = NOT_GIVEN, - webhooks: Optional[List[str]] | NotGiven = NOT_GIVEN, - welcome_message: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Chatbot: - """ - 更新某个 Bot - - Args: - avatar_url: 头像 URL - - color_theme: 颜色主题 - - datasource_ids: 数据源 ID,目前只支持 1 个数据源。 - - debug: 调试模式 - - extapi_ids: 扩展 API ID 列表,扩展 API ID 的逗号分隔列表。 - - interaction_rules: 交互规则列表,用于定义 bot 的行为规则 - - magic_input: 魔法提示词 - - max_rows: 最大返回行数,默认不限制 - - name: 名称,不超过 64 个字符 - - publish: 是否公开 - - query_balance: bot 的查询次数,默认是 None,表示无限次查询,入参为大于等于 0 的整数 - - sample_questions: 示例问题列表 - - webhooks: Webhook URL 列表 - - welcome_message: 欢迎消息 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not bot_id: - raise ValueError(f"Expected a non-empty value for `bot_id` but received {bot_id!r}") - return await self._patch( - f"/v1/bots/{bot_id}", - body=await async_maybe_transform( - { - "avatar_url": avatar_url, - "color_theme": color_theme, - "datasource_ids": datasource_ids, - "debug": debug, - "extapi_ids": extapi_ids, - "interaction_rules": interaction_rules, - "magic_input": magic_input, - "max_rows": max_rows, - "name": name, - "publish": publish, - "query_balance": query_balance, - "sample_questions": sample_questions, - "webhooks": webhooks, - "welcome_message": welcome_message, - }, - bot_update_params.BotUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Chatbot, - ) - - def list( - self, - *, - bot_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[Chatbot, AsyncPage[Chatbot]]: - """ - 查询所有 Bot - - Args: - bot_ids: Bot ID - - name: 名称 - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/bots", - page=AsyncPage[Chatbot], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "bot_ids": bot_ids, - "name": name, - "page": page, - "size": size, - }, - bot_list_params.BotListParams, - ), - ), - model=Chatbot, - ) - - async def delete( - self, - bot_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 删除某个 Bot - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not bot_id: - raise ValueError(f"Expected a non-empty value for `bot_id` but received {bot_id!r}") - return await self._delete( - f"/v1/bots/{bot_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - async def invite( - self, - bot_id: str, - *, - project_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 邀请用户加入对话 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not bot_id: - raise ValueError(f"Expected a non-empty value for `bot_id` but received {bot_id!r}") - return await self._post( - f"/v1/bots/{bot_id}/invite", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"project_id": project_id}, bot_invite_params.BotInviteParams), - ), - cast_to=object, - ) - - -class BotsResourceWithRawResponse: - def __init__(self, bots: BotsResource) -> None: - self._bots = bots - - self.create = to_raw_response_wrapper( - bots.create, - ) - self.retrieve = to_raw_response_wrapper( - bots.retrieve, - ) - self.update = to_raw_response_wrapper( - bots.update, - ) - self.list = to_raw_response_wrapper( - bots.list, - ) - self.delete = to_raw_response_wrapper( - bots.delete, - ) - self.invite = to_raw_response_wrapper( - bots.invite, - ) - - -class AsyncBotsResourceWithRawResponse: - def __init__(self, bots: AsyncBotsResource) -> None: - self._bots = bots - - self.create = async_to_raw_response_wrapper( - bots.create, - ) - self.retrieve = async_to_raw_response_wrapper( - bots.retrieve, - ) - self.update = async_to_raw_response_wrapper( - bots.update, - ) - self.list = async_to_raw_response_wrapper( - bots.list, - ) - self.delete = async_to_raw_response_wrapper( - bots.delete, - ) - self.invite = async_to_raw_response_wrapper( - bots.invite, - ) - - -class BotsResourceWithStreamingResponse: - def __init__(self, bots: BotsResource) -> None: - self._bots = bots - - self.create = to_streamed_response_wrapper( - bots.create, - ) - self.retrieve = to_streamed_response_wrapper( - bots.retrieve, - ) - self.update = to_streamed_response_wrapper( - bots.update, - ) - self.list = to_streamed_response_wrapper( - bots.list, - ) - self.delete = to_streamed_response_wrapper( - bots.delete, - ) - self.invite = to_streamed_response_wrapper( - bots.invite, - ) - - -class AsyncBotsResourceWithStreamingResponse: - def __init__(self, bots: AsyncBotsResource) -> None: - self._bots = bots - - self.create = async_to_streamed_response_wrapper( - bots.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - bots.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - bots.update, - ) - self.list = async_to_streamed_response_wrapper( - bots.list, - ) - self.delete = async_to_streamed_response_wrapper( - bots.delete, - ) - self.invite = async_to_streamed_response_wrapper( - bots.invite, - ) diff --git a/src/asktable/resources/business_glossary.py b/src/asktable/resources/business_glossary.py deleted file mode 100644 index 2eed15db..00000000 --- a/src/asktable/resources/business_glossary.py +++ /dev/null @@ -1,566 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Iterable, Optional - -import httpx - -from ..types import business_glossary_list_params, business_glossary_create_params, business_glossary_update_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..pagination import SyncPage, AsyncPage -from ..types.entry import Entry -from .._base_client import AsyncPaginator, make_request_options -from ..types.entry_with_definition import EntryWithDefinition -from ..types.business_glossary_create_response import BusinessGlossaryCreateResponse - -__all__ = ["BusinessGlossaryResource", "AsyncBusinessGlossaryResource"] - - -class BusinessGlossaryResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> BusinessGlossaryResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return BusinessGlossaryResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> BusinessGlossaryResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return BusinessGlossaryResourceWithStreamingResponse(self) - - def create( - self, - *, - body: Iterable[business_glossary_create_params.Body], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> BusinessGlossaryCreateResponse: - """ - 创建业务术语 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/business-glossary", - body=maybe_transform(body, Iterable[business_glossary_create_params.Body]), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BusinessGlossaryCreateResponse, - ) - - def retrieve( - self, - entry_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> EntryWithDefinition: - """ - 获取某个业务术语 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not entry_id: - raise ValueError(f"Expected a non-empty value for `entry_id` but received {entry_id!r}") - return self._get( - f"/v1/business-glossary/{entry_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EntryWithDefinition, - ) - - def update( - self, - entry_id: str, - *, - active: Optional[bool] | NotGiven = NOT_GIVEN, - aliases: Optional[List[str]] | NotGiven = NOT_GIVEN, - definition: Optional[str] | NotGiven = NOT_GIVEN, - payload: Optional[object] | NotGiven = NOT_GIVEN, - term: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Entry: - """ - 更新业务术语 - - Args: - active: 业务术语是否生效 - - aliases: 业务术语同义词 - - definition: 业务术语定义 - - payload: 业务术语元数据 - - term: 业务术语 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not entry_id: - raise ValueError(f"Expected a non-empty value for `entry_id` but received {entry_id!r}") - return self._patch( - f"/v1/business-glossary/{entry_id}", - body=maybe_transform( - { - "active": active, - "aliases": aliases, - "definition": definition, - "payload": payload, - "term": term, - }, - business_glossary_update_params.BusinessGlossaryUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Entry, - ) - - def list( - self, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - term: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[EntryWithDefinition]: - """ - 查询所有业务术语 - - Args: - page: Page number - - size: Page size - - term: 术语名称 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/business-glossary", - page=SyncPage[EntryWithDefinition], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - "term": term, - }, - business_glossary_list_params.BusinessGlossaryListParams, - ), - ), - model=EntryWithDefinition, - ) - - def delete( - self, - entry_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 删除某个业务术语 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not entry_id: - raise ValueError(f"Expected a non-empty value for `entry_id` but received {entry_id!r}") - return self._delete( - f"/v1/business-glossary/{entry_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - -class AsyncBusinessGlossaryResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncBusinessGlossaryResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncBusinessGlossaryResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncBusinessGlossaryResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncBusinessGlossaryResourceWithStreamingResponse(self) - - async def create( - self, - *, - body: Iterable[business_glossary_create_params.Body], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> BusinessGlossaryCreateResponse: - """ - 创建业务术语 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/business-glossary", - body=await async_maybe_transform(body, Iterable[business_glossary_create_params.Body]), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BusinessGlossaryCreateResponse, - ) - - async def retrieve( - self, - entry_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> EntryWithDefinition: - """ - 获取某个业务术语 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not entry_id: - raise ValueError(f"Expected a non-empty value for `entry_id` but received {entry_id!r}") - return await self._get( - f"/v1/business-glossary/{entry_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EntryWithDefinition, - ) - - async def update( - self, - entry_id: str, - *, - active: Optional[bool] | NotGiven = NOT_GIVEN, - aliases: Optional[List[str]] | NotGiven = NOT_GIVEN, - definition: Optional[str] | NotGiven = NOT_GIVEN, - payload: Optional[object] | NotGiven = NOT_GIVEN, - term: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Entry: - """ - 更新业务术语 - - Args: - active: 业务术语是否生效 - - aliases: 业务术语同义词 - - definition: 业务术语定义 - - payload: 业务术语元数据 - - term: 业务术语 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not entry_id: - raise ValueError(f"Expected a non-empty value for `entry_id` but received {entry_id!r}") - return await self._patch( - f"/v1/business-glossary/{entry_id}", - body=await async_maybe_transform( - { - "active": active, - "aliases": aliases, - "definition": definition, - "payload": payload, - "term": term, - }, - business_glossary_update_params.BusinessGlossaryUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Entry, - ) - - def list( - self, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - term: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[EntryWithDefinition, AsyncPage[EntryWithDefinition]]: - """ - 查询所有业务术语 - - Args: - page: Page number - - size: Page size - - term: 术语名称 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/business-glossary", - page=AsyncPage[EntryWithDefinition], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - "term": term, - }, - business_glossary_list_params.BusinessGlossaryListParams, - ), - ), - model=EntryWithDefinition, - ) - - async def delete( - self, - entry_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 删除某个业务术语 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not entry_id: - raise ValueError(f"Expected a non-empty value for `entry_id` but received {entry_id!r}") - return await self._delete( - f"/v1/business-glossary/{entry_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - -class BusinessGlossaryResourceWithRawResponse: - def __init__(self, business_glossary: BusinessGlossaryResource) -> None: - self._business_glossary = business_glossary - - self.create = to_raw_response_wrapper( - business_glossary.create, - ) - self.retrieve = to_raw_response_wrapper( - business_glossary.retrieve, - ) - self.update = to_raw_response_wrapper( - business_glossary.update, - ) - self.list = to_raw_response_wrapper( - business_glossary.list, - ) - self.delete = to_raw_response_wrapper( - business_glossary.delete, - ) - - -class AsyncBusinessGlossaryResourceWithRawResponse: - def __init__(self, business_glossary: AsyncBusinessGlossaryResource) -> None: - self._business_glossary = business_glossary - - self.create = async_to_raw_response_wrapper( - business_glossary.create, - ) - self.retrieve = async_to_raw_response_wrapper( - business_glossary.retrieve, - ) - self.update = async_to_raw_response_wrapper( - business_glossary.update, - ) - self.list = async_to_raw_response_wrapper( - business_glossary.list, - ) - self.delete = async_to_raw_response_wrapper( - business_glossary.delete, - ) - - -class BusinessGlossaryResourceWithStreamingResponse: - def __init__(self, business_glossary: BusinessGlossaryResource) -> None: - self._business_glossary = business_glossary - - self.create = to_streamed_response_wrapper( - business_glossary.create, - ) - self.retrieve = to_streamed_response_wrapper( - business_glossary.retrieve, - ) - self.update = to_streamed_response_wrapper( - business_glossary.update, - ) - self.list = to_streamed_response_wrapper( - business_glossary.list, - ) - self.delete = to_streamed_response_wrapper( - business_glossary.delete, - ) - - -class AsyncBusinessGlossaryResourceWithStreamingResponse: - def __init__(self, business_glossary: AsyncBusinessGlossaryResource) -> None: - self._business_glossary = business_glossary - - self.create = async_to_streamed_response_wrapper( - business_glossary.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - business_glossary.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - business_glossary.update, - ) - self.list = async_to_streamed_response_wrapper( - business_glossary.list, - ) - self.delete = async_to_streamed_response_wrapper( - business_glossary.delete, - ) diff --git a/src/asktable/resources/caches.py b/src/asktable/resources/caches.py deleted file mode 100644 index b89b7d6b..00000000 --- a/src/asktable/resources/caches.py +++ /dev/null @@ -1,164 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from .._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from .._base_client import make_request_options - -__all__ = ["CachesResource", "AsyncCachesResource"] - - -class CachesResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> CachesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return CachesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CachesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return CachesResourceWithStreamingResponse(self) - - def delete( - self, - cache_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - 清除缓存 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not cache_id: - raise ValueError(f"Expected a non-empty value for `cache_id` but received {cache_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/v1/caches/{cache_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncCachesResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncCachesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncCachesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCachesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncCachesResourceWithStreamingResponse(self) - - async def delete( - self, - cache_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - 清除缓存 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not cache_id: - raise ValueError(f"Expected a non-empty value for `cache_id` but received {cache_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/v1/caches/{cache_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class CachesResourceWithRawResponse: - def __init__(self, caches: CachesResource) -> None: - self._caches = caches - - self.delete = to_raw_response_wrapper( - caches.delete, - ) - - -class AsyncCachesResourceWithRawResponse: - def __init__(self, caches: AsyncCachesResource) -> None: - self._caches = caches - - self.delete = async_to_raw_response_wrapper( - caches.delete, - ) - - -class CachesResourceWithStreamingResponse: - def __init__(self, caches: CachesResource) -> None: - self._caches = caches - - self.delete = to_streamed_response_wrapper( - caches.delete, - ) - - -class AsyncCachesResourceWithStreamingResponse: - def __init__(self, caches: AsyncCachesResource) -> None: - self._caches = caches - - self.delete = async_to_streamed_response_wrapper( - caches.delete, - ) diff --git a/src/asktable/resources/chats/__init__.py b/src/asktable/resources/chats/__init__.py deleted file mode 100644 index f24e63d9..00000000 --- a/src/asktable/resources/chats/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .chats import ( - ChatsResource, - AsyncChatsResource, - ChatsResourceWithRawResponse, - AsyncChatsResourceWithRawResponse, - ChatsResourceWithStreamingResponse, - AsyncChatsResourceWithStreamingResponse, -) -from .messages import ( - MessagesResource, - AsyncMessagesResource, - MessagesResourceWithRawResponse, - AsyncMessagesResourceWithRawResponse, - MessagesResourceWithStreamingResponse, - AsyncMessagesResourceWithStreamingResponse, -) - -__all__ = [ - "MessagesResource", - "AsyncMessagesResource", - "MessagesResourceWithRawResponse", - "AsyncMessagesResourceWithRawResponse", - "MessagesResourceWithStreamingResponse", - "AsyncMessagesResourceWithStreamingResponse", - "ChatsResource", - "AsyncChatsResource", - "ChatsResourceWithRawResponse", - "AsyncChatsResourceWithRawResponse", - "ChatsResourceWithStreamingResponse", - "AsyncChatsResourceWithStreamingResponse", -] diff --git a/src/asktable/resources/chats/chats.py b/src/asktable/resources/chats/chats.py deleted file mode 100644 index fd159838..00000000 --- a/src/asktable/resources/chats/chats.py +++ /dev/null @@ -1,513 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional - -import httpx - -from ...types import chat_list_params, chat_create_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from ..._utils import maybe_transform, async_maybe_transform -from .messages import ( - MessagesResource, - AsyncMessagesResource, - MessagesResourceWithRawResponse, - AsyncMessagesResourceWithRawResponse, - MessagesResourceWithStreamingResponse, - AsyncMessagesResourceWithStreamingResponse, -) -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncPage, AsyncPage -from ...types.chat import Chat -from ..._base_client import AsyncPaginator, make_request_options -from ...types.chat_retrieve_response import ChatRetrieveResponse - -__all__ = ["ChatsResource", "AsyncChatsResource"] - - -class ChatsResource(SyncAPIResource): - @cached_property - def messages(self) -> MessagesResource: - return MessagesResource(self._client) - - @cached_property - def with_raw_response(self) -> ChatsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return ChatsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ChatsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return ChatsResourceWithStreamingResponse(self) - - def create( - self, - *, - bot_id: Optional[str] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[Dict[str, Union[str, int, bool]]] | NotGiven = NOT_GIVEN, - user_profile: Optional[Dict[str, Union[str, int, bool]]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Chat: - """ - 创建对话 - - Args: - bot_id: 机器人 ID,如果需要使用高级功能,请使用 bot_id 来创建对话。在机器人中你可以定义 - 可以访问的数据、可以执行的任务以及是否开启调试模式等设置。 - - name: New name for the chat - - role_id: 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - user_profile: 用户信息,用于在对话中传递用户的信息,用 Key-Value 形式传递 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/chats", - body=maybe_transform( - { - "bot_id": bot_id, - "name": name, - "role_id": role_id, - "role_variables": role_variables, - "user_profile": user_profile, - }, - chat_create_params.ChatCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Chat, - ) - - def retrieve( - self, - chat_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ChatRetrieveResponse: - """ - 获取某个对话 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - return self._get( - f"/v1/chats/{chat_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatRetrieveResponse, - ) - - def list( - self, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[Chat]: - """ - 查询对话列表 - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/chats", - page=SyncPage[Chat], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - chat_list_params.ChatListParams, - ), - ), - model=Chat, - ) - - def delete( - self, - chat_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - 删除某个对话(包含消息) - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/v1/chats/{chat_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncChatsResource(AsyncAPIResource): - @cached_property - def messages(self) -> AsyncMessagesResource: - return AsyncMessagesResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncChatsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncChatsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncChatsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncChatsResourceWithStreamingResponse(self) - - async def create( - self, - *, - bot_id: Optional[str] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[Dict[str, Union[str, int, bool]]] | NotGiven = NOT_GIVEN, - user_profile: Optional[Dict[str, Union[str, int, bool]]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Chat: - """ - 创建对话 - - Args: - bot_id: 机器人 ID,如果需要使用高级功能,请使用 bot_id 来创建对话。在机器人中你可以定义 - 可以访问的数据、可以执行的任务以及是否开启调试模式等设置。 - - name: New name for the chat - - role_id: 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - user_profile: 用户信息,用于在对话中传递用户的信息,用 Key-Value 形式传递 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/chats", - body=await async_maybe_transform( - { - "bot_id": bot_id, - "name": name, - "role_id": role_id, - "role_variables": role_variables, - "user_profile": user_profile, - }, - chat_create_params.ChatCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Chat, - ) - - async def retrieve( - self, - chat_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ChatRetrieveResponse: - """ - 获取某个对话 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - return await self._get( - f"/v1/chats/{chat_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ChatRetrieveResponse, - ) - - def list( - self, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[Chat, AsyncPage[Chat]]: - """ - 查询对话列表 - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/chats", - page=AsyncPage[Chat], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - chat_list_params.ChatListParams, - ), - ), - model=Chat, - ) - - async def delete( - self, - chat_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - 删除某个对话(包含消息) - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/v1/chats/{chat_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class ChatsResourceWithRawResponse: - def __init__(self, chats: ChatsResource) -> None: - self._chats = chats - - self.create = to_raw_response_wrapper( - chats.create, - ) - self.retrieve = to_raw_response_wrapper( - chats.retrieve, - ) - self.list = to_raw_response_wrapper( - chats.list, - ) - self.delete = to_raw_response_wrapper( - chats.delete, - ) - - @cached_property - def messages(self) -> MessagesResourceWithRawResponse: - return MessagesResourceWithRawResponse(self._chats.messages) - - -class AsyncChatsResourceWithRawResponse: - def __init__(self, chats: AsyncChatsResource) -> None: - self._chats = chats - - self.create = async_to_raw_response_wrapper( - chats.create, - ) - self.retrieve = async_to_raw_response_wrapper( - chats.retrieve, - ) - self.list = async_to_raw_response_wrapper( - chats.list, - ) - self.delete = async_to_raw_response_wrapper( - chats.delete, - ) - - @cached_property - def messages(self) -> AsyncMessagesResourceWithRawResponse: - return AsyncMessagesResourceWithRawResponse(self._chats.messages) - - -class ChatsResourceWithStreamingResponse: - def __init__(self, chats: ChatsResource) -> None: - self._chats = chats - - self.create = to_streamed_response_wrapper( - chats.create, - ) - self.retrieve = to_streamed_response_wrapper( - chats.retrieve, - ) - self.list = to_streamed_response_wrapper( - chats.list, - ) - self.delete = to_streamed_response_wrapper( - chats.delete, - ) - - @cached_property - def messages(self) -> MessagesResourceWithStreamingResponse: - return MessagesResourceWithStreamingResponse(self._chats.messages) - - -class AsyncChatsResourceWithStreamingResponse: - def __init__(self, chats: AsyncChatsResource) -> None: - self._chats = chats - - self.create = async_to_streamed_response_wrapper( - chats.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - chats.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - chats.list, - ) - self.delete = async_to_streamed_response_wrapper( - chats.delete, - ) - - @cached_property - def messages(self) -> AsyncMessagesResourceWithStreamingResponse: - return AsyncMessagesResourceWithStreamingResponse(self._chats.messages) diff --git a/src/asktable/resources/chats/messages.py b/src/asktable/resources/chats/messages.py deleted file mode 100644 index 7c3ca18a..00000000 --- a/src/asktable/resources/chats/messages.py +++ /dev/null @@ -1,398 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Any, cast - -import httpx - -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncPage, AsyncPage -from ...types.chats import message_list_params, message_create_params -from ..._base_client import AsyncPaginator, make_request_options -from ...types.chats.message_list_response import MessageListResponse -from ...types.chats.message_create_response import MessageCreateResponse -from ...types.chats.message_retrieve_response import MessageRetrieveResponse - -__all__ = ["MessagesResource", "AsyncMessagesResource"] - - -class MessagesResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> MessagesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return MessagesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> MessagesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return MessagesResourceWithStreamingResponse(self) - - def create( - self, - chat_id: str, - *, - question: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> MessageCreateResponse: - """ - Send a message to the chat - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - return cast( - MessageCreateResponse, - self._post( - f"/v1/chats/{chat_id}/messages", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"question": question}, message_create_params.MessageCreateParams), - ), - cast_to=cast( - Any, MessageCreateResponse - ), # Union types cannot be passed in as arguments in the type system - ), - ) - - def retrieve( - self, - message_id: str, - *, - chat_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> MessageRetrieveResponse: - """ - 查询某条消息 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - return cast( - MessageRetrieveResponse, - self._get( - f"/v1/chats/{chat_id}/messages/{message_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=cast( - Any, MessageRetrieveResponse - ), # Union types cannot be passed in as arguments in the type system - ), - ) - - def list( - self, - chat_id: str, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[MessageListResponse]: - """ - 查询所有的消息 - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - return self._get_api_list( - f"/v1/chats/{chat_id}/messages", - page=SyncPage[MessageListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - message_list_params.MessageListParams, - ), - ), - model=cast(Any, MessageListResponse), # Union types cannot be passed in as arguments in the type system - ) - - -class AsyncMessagesResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncMessagesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncMessagesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncMessagesResourceWithStreamingResponse(self) - - async def create( - self, - chat_id: str, - *, - question: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> MessageCreateResponse: - """ - Send a message to the chat - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - return cast( - MessageCreateResponse, - await self._post( - f"/v1/chats/{chat_id}/messages", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"question": question}, message_create_params.MessageCreateParams - ), - ), - cast_to=cast( - Any, MessageCreateResponse - ), # Union types cannot be passed in as arguments in the type system - ), - ) - - async def retrieve( - self, - message_id: str, - *, - chat_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> MessageRetrieveResponse: - """ - 查询某条消息 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - return cast( - MessageRetrieveResponse, - await self._get( - f"/v1/chats/{chat_id}/messages/{message_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=cast( - Any, MessageRetrieveResponse - ), # Union types cannot be passed in as arguments in the type system - ), - ) - - def list( - self, - chat_id: str, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[MessageListResponse, AsyncPage[MessageListResponse]]: - """ - 查询所有的消息 - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not chat_id: - raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") - return self._get_api_list( - f"/v1/chats/{chat_id}/messages", - page=AsyncPage[MessageListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - message_list_params.MessageListParams, - ), - ), - model=cast(Any, MessageListResponse), # Union types cannot be passed in as arguments in the type system - ) - - -class MessagesResourceWithRawResponse: - def __init__(self, messages: MessagesResource) -> None: - self._messages = messages - - self.create = to_raw_response_wrapper( - messages.create, - ) - self.retrieve = to_raw_response_wrapper( - messages.retrieve, - ) - self.list = to_raw_response_wrapper( - messages.list, - ) - - -class AsyncMessagesResourceWithRawResponse: - def __init__(self, messages: AsyncMessagesResource) -> None: - self._messages = messages - - self.create = async_to_raw_response_wrapper( - messages.create, - ) - self.retrieve = async_to_raw_response_wrapper( - messages.retrieve, - ) - self.list = async_to_raw_response_wrapper( - messages.list, - ) - - -class MessagesResourceWithStreamingResponse: - def __init__(self, messages: MessagesResource) -> None: - self._messages = messages - - self.create = to_streamed_response_wrapper( - messages.create, - ) - self.retrieve = to_streamed_response_wrapper( - messages.retrieve, - ) - self.list = to_streamed_response_wrapper( - messages.list, - ) - - -class AsyncMessagesResourceWithStreamingResponse: - def __init__(self, messages: AsyncMessagesResource) -> None: - self._messages = messages - - self.create = async_to_streamed_response_wrapper( - messages.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - messages.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - messages.list, - ) diff --git a/src/asktable/resources/dataframes.py b/src/asktable/resources/dataframes.py index 4320689d..36cee9e9 100644 --- a/src/asktable/resources/dataframes.py +++ b/src/asktable/resources/dataframes.py @@ -4,7 +4,8 @@ import httpx -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Query, Headers, NotGiven, not_given +from .._utils import path_template from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -48,7 +49,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DataframeRetrieveResponse: """ Get Dataframe @@ -65,7 +66,7 @@ def retrieve( if not dataframe_id: raise ValueError(f"Expected a non-empty value for `dataframe_id` but received {dataframe_id!r}") return self._get( - f"/v1/dataframes/{dataframe_id}", + path_template("/v1/dataframes/{dataframe_id}", dataframe_id=dataframe_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -102,7 +103,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DataframeRetrieveResponse: """ Get Dataframe @@ -119,7 +120,7 @@ async def retrieve( if not dataframe_id: raise ValueError(f"Expected a non-empty value for `dataframe_id` but received {dataframe_id!r}") return await self._get( - f"/v1/dataframes/{dataframe_id}", + path_template("/v1/dataframes/{dataframe_id}", dataframe_id=dataframe_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/asktable/resources/datasources/datasources.py b/src/asktable/resources/datasources/datasources.py index 239b7943..a0292676 100644 --- a/src/asktable/resources/datasources/datasources.py +++ b/src/asktable/resources/datasources/datasources.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Mapping, Optional, cast +from typing import Dict, Optional from typing_extensions import Literal import httpx @@ -30,8 +30,8 @@ IndexesResourceWithStreamingResponse, AsyncIndexesResourceWithStreamingResponse, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -58,16 +58,21 @@ class DatasourcesResource(SyncAPIResource): + """数据源管理""" + @cached_property def meta(self) -> MetaResource: + """数据源管理""" return MetaResource(self._client) @cached_property def upload_params(self) -> UploadParamsResource: + """数据源管理""" return UploadParamsResource(self._client) @cached_property def indexes(self) -> IndexesResource: + """索引管理""" return IndexesResource(self._client) @cached_property @@ -114,15 +119,29 @@ def create( "databend", "sqlserver", "mogdb", + "hologres", + "maxcompute", + "gaussdb", + "tdsqlmysql", + "tdsqlpg", + "kingbasees", + "gbase8c", + "yashandb", + "gbase8a", + "gaussdbdws", + "bitable", + "dap", + "duckdb", + "workbook", ], - access_config: Optional[datasource_create_params.AccessConfig] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + access_config: Optional[datasource_create_params.AccessConfig] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Datasource: """ 创建一个新的数据源 @@ -167,7 +186,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DatasourceRetrieveResponse: """ 根据 id 获取指定数据源 @@ -184,7 +203,7 @@ def retrieve( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._get( - f"/v1/datasources/{datasource_id}", + path_template("/v1/datasources/{datasource_id}", datasource_id=datasource_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -195,8 +214,8 @@ def update( self, datasource_id: str, *, - access_config: Optional[datasource_update_params.AccessConfig] | NotGiven = NOT_GIVEN, - desc: Optional[str] | NotGiven = NOT_GIVEN, + access_config: Optional[datasource_update_params.AccessConfig] | Omit = omit, + desc: Optional[str] | Omit = omit, engine: Optional[ Literal[ "mysql", @@ -220,22 +239,37 @@ def update( "databend", "sqlserver", "mogdb", + "hologres", + "maxcompute", + "gaussdb", + "tdsqlmysql", + "tdsqlpg", + "kingbasees", + "gbase8c", + "yashandb", + "gbase8a", + "gaussdbdws", + "bitable", + "dap", + "duckdb", + "workbook", ] ] - | NotGiven = NOT_GIVEN, - field_count: Optional[int] | NotGiven = NOT_GIVEN, - meta_error: Optional[str] | NotGiven = NOT_GIVEN, - meta_status: Optional[Literal["processing", "failed", "success", "unprocessed"]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - sample_questions: Optional[str] | NotGiven = NOT_GIVEN, - schema_count: Optional[int] | NotGiven = NOT_GIVEN, - table_count: Optional[int] | NotGiven = NOT_GIVEN, + | Omit = omit, + field_count: Optional[int] | Omit = omit, + meta_status: Optional[Literal["unavailable", "available"]] | Omit = omit, + name: Optional[str] | Omit = omit, + sample_questions: Optional[SequenceNotStr[str]] | Omit = omit, + schema_count: Optional[int] | Omit = omit, + sync_error: Optional[Dict[str, object]] | Omit = omit, + sync_status: Optional[Literal["processing", "success", "failed", "warning"]] | Omit = omit, + table_count: Optional[int] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Datasource: """ 更新指定数据源信息 @@ -249,9 +283,7 @@ def update( field_count: 字段数量 - meta_error: 元数据处理错误 - - meta_status: 元数据处理状态 + meta_status: 数据源可用性 name: 数据源的名称 @@ -259,6 +291,10 @@ def update( schema_count: 库数量 + sync_error: 同步错误信息 + + sync_status: 同步状态 + table_count: 表数量 extra_headers: Send extra headers @@ -272,18 +308,19 @@ def update( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._patch( - f"/v1/datasources/{datasource_id}", + path_template("/v1/datasources/{datasource_id}", datasource_id=datasource_id), body=maybe_transform( { "access_config": access_config, "desc": desc, "engine": engine, "field_count": field_count, - "meta_error": meta_error, "meta_status": meta_status, "name": name, "sample_questions": sample_questions, "schema_count": schema_count, + "sync_error": sync_error, + "sync_status": sync_status, "table_count": table_count, }, datasource_update_params.DatasourceUpdateParams, @@ -297,15 +334,15 @@ def update( def list( self, *, - name: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, + name: Optional[str] | Omit = omit, + page: int | Omit = omit, + size: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Datasource]: """ 获取所有的数据源 @@ -352,7 +389,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 根据 id 删除指定数据源 @@ -369,7 +406,7 @@ def delete( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._delete( - f"/v1/datasources/{datasource_id}", + path_template("/v1/datasources/{datasource_id}", datasource_id=datasource_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -380,13 +417,13 @@ def add_file( self, datasource_id: str, *, - file: FileTypes, + file: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 为数据源添加文件 @@ -402,16 +439,13 @@ def add_file( """ if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") - body = deepcopy_minimal({"file": file}) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) # It should be noted that the actual Content-Type header that will be # sent to the server will contain a `boundary` parameter, e.g. # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( - f"/v1/datasources/{datasource_id}/files", - body=maybe_transform(body, datasource_add_file_params.DatasourceAddFileParams), - files=files, + path_template("/v1/datasources/{datasource_id}/files", datasource_id=datasource_id), + body=maybe_transform({"file": file}, datasource_add_file_params.DatasourceAddFileParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -428,7 +462,7 @@ def delete_file( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 删除数据源的单个文件 @@ -447,7 +481,9 @@ def delete_file( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._delete( - f"/v1/datasources/{datasource_id}/files/{file_id}", + path_template( + "/v1/datasources/{datasource_id}/files/{file_id}", datasource_id=datasource_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -463,7 +499,7 @@ def retrieve_runtime_meta( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DatasourceRetrieveRuntimeMetaResponse: """ 获取指定数据源的运行时元数据 @@ -480,7 +516,7 @@ def retrieve_runtime_meta( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._get( - f"/v1/datasources/{datasource_id}/runtime-meta", + path_template("/v1/datasources/{datasource_id}/runtime-meta", datasource_id=datasource_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -497,14 +533,14 @@ def update_field( identifiable_type: Optional[ Literal["plain", "person_name", "email", "ssn", "id", "phone", "address", "company", "bank_card"] ] - | NotGiven = NOT_GIVEN, - visibility: Optional[bool] | NotGiven = NOT_GIVEN, + | Omit = omit, + visibility: Optional[bool] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 更新数据源的某个字段的描述 @@ -525,7 +561,7 @@ def update_field( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._patch( - f"/v1/datasources/{datasource_id}/field", + path_template("/v1/datasources/{datasource_id}/field", datasource_id=datasource_id), body=maybe_transform( { "identifiable_type": identifiable_type, @@ -552,16 +588,21 @@ def update_field( class AsyncDatasourcesResource(AsyncAPIResource): + """数据源管理""" + @cached_property def meta(self) -> AsyncMetaResource: + """数据源管理""" return AsyncMetaResource(self._client) @cached_property def upload_params(self) -> AsyncUploadParamsResource: + """数据源管理""" return AsyncUploadParamsResource(self._client) @cached_property def indexes(self) -> AsyncIndexesResource: + """索引管理""" return AsyncIndexesResource(self._client) @cached_property @@ -608,15 +649,29 @@ async def create( "databend", "sqlserver", "mogdb", + "hologres", + "maxcompute", + "gaussdb", + "tdsqlmysql", + "tdsqlpg", + "kingbasees", + "gbase8c", + "yashandb", + "gbase8a", + "gaussdbdws", + "bitable", + "dap", + "duckdb", + "workbook", ], - access_config: Optional[datasource_create_params.AccessConfig] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + access_config: Optional[datasource_create_params.AccessConfig] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Datasource: """ 创建一个新的数据源 @@ -661,7 +716,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DatasourceRetrieveResponse: """ 根据 id 获取指定数据源 @@ -678,7 +733,7 @@ async def retrieve( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._get( - f"/v1/datasources/{datasource_id}", + path_template("/v1/datasources/{datasource_id}", datasource_id=datasource_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -689,8 +744,8 @@ async def update( self, datasource_id: str, *, - access_config: Optional[datasource_update_params.AccessConfig] | NotGiven = NOT_GIVEN, - desc: Optional[str] | NotGiven = NOT_GIVEN, + access_config: Optional[datasource_update_params.AccessConfig] | Omit = omit, + desc: Optional[str] | Omit = omit, engine: Optional[ Literal[ "mysql", @@ -714,22 +769,37 @@ async def update( "databend", "sqlserver", "mogdb", + "hologres", + "maxcompute", + "gaussdb", + "tdsqlmysql", + "tdsqlpg", + "kingbasees", + "gbase8c", + "yashandb", + "gbase8a", + "gaussdbdws", + "bitable", + "dap", + "duckdb", + "workbook", ] ] - | NotGiven = NOT_GIVEN, - field_count: Optional[int] | NotGiven = NOT_GIVEN, - meta_error: Optional[str] | NotGiven = NOT_GIVEN, - meta_status: Optional[Literal["processing", "failed", "success", "unprocessed"]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - sample_questions: Optional[str] | NotGiven = NOT_GIVEN, - schema_count: Optional[int] | NotGiven = NOT_GIVEN, - table_count: Optional[int] | NotGiven = NOT_GIVEN, + | Omit = omit, + field_count: Optional[int] | Omit = omit, + meta_status: Optional[Literal["unavailable", "available"]] | Omit = omit, + name: Optional[str] | Omit = omit, + sample_questions: Optional[SequenceNotStr[str]] | Omit = omit, + schema_count: Optional[int] | Omit = omit, + sync_error: Optional[Dict[str, object]] | Omit = omit, + sync_status: Optional[Literal["processing", "success", "failed", "warning"]] | Omit = omit, + table_count: Optional[int] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Datasource: """ 更新指定数据源信息 @@ -743,9 +813,7 @@ async def update( field_count: 字段数量 - meta_error: 元数据处理错误 - - meta_status: 元数据处理状态 + meta_status: 数据源可用性 name: 数据源的名称 @@ -753,6 +821,10 @@ async def update( schema_count: 库数量 + sync_error: 同步错误信息 + + sync_status: 同步状态 + table_count: 表数量 extra_headers: Send extra headers @@ -766,18 +838,19 @@ async def update( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._patch( - f"/v1/datasources/{datasource_id}", + path_template("/v1/datasources/{datasource_id}", datasource_id=datasource_id), body=await async_maybe_transform( { "access_config": access_config, "desc": desc, "engine": engine, "field_count": field_count, - "meta_error": meta_error, "meta_status": meta_status, "name": name, "sample_questions": sample_questions, "schema_count": schema_count, + "sync_error": sync_error, + "sync_status": sync_status, "table_count": table_count, }, datasource_update_params.DatasourceUpdateParams, @@ -791,15 +864,15 @@ async def update( def list( self, *, - name: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, + name: Optional[str] | Omit = omit, + page: int | Omit = omit, + size: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Datasource, AsyncPage[Datasource]]: """ 获取所有的数据源 @@ -846,7 +919,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 根据 id 删除指定数据源 @@ -863,7 +936,7 @@ async def delete( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._delete( - f"/v1/datasources/{datasource_id}", + path_template("/v1/datasources/{datasource_id}", datasource_id=datasource_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -874,13 +947,13 @@ async def add_file( self, datasource_id: str, *, - file: FileTypes, + file: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 为数据源添加文件 @@ -896,16 +969,13 @@ async def add_file( """ if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") - body = deepcopy_minimal({"file": file}) - files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) # It should be noted that the actual Content-Type header that will be # sent to the server will contain a `boundary` parameter, e.g. # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( - f"/v1/datasources/{datasource_id}/files", - body=await async_maybe_transform(body, datasource_add_file_params.DatasourceAddFileParams), - files=files, + path_template("/v1/datasources/{datasource_id}/files", datasource_id=datasource_id), + body=await async_maybe_transform({"file": file}, datasource_add_file_params.DatasourceAddFileParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -922,7 +992,7 @@ async def delete_file( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 删除数据源的单个文件 @@ -941,7 +1011,9 @@ async def delete_file( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._delete( - f"/v1/datasources/{datasource_id}/files/{file_id}", + path_template( + "/v1/datasources/{datasource_id}/files/{file_id}", datasource_id=datasource_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -957,7 +1029,7 @@ async def retrieve_runtime_meta( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> DatasourceRetrieveRuntimeMetaResponse: """ 获取指定数据源的运行时元数据 @@ -974,7 +1046,7 @@ async def retrieve_runtime_meta( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._get( - f"/v1/datasources/{datasource_id}/runtime-meta", + path_template("/v1/datasources/{datasource_id}/runtime-meta", datasource_id=datasource_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -991,14 +1063,14 @@ async def update_field( identifiable_type: Optional[ Literal["plain", "person_name", "email", "ssn", "id", "phone", "address", "company", "bank_card"] ] - | NotGiven = NOT_GIVEN, - visibility: Optional[bool] | NotGiven = NOT_GIVEN, + | Omit = omit, + visibility: Optional[bool] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 更新数据源的某个字段的描述 @@ -1019,7 +1091,7 @@ async def update_field( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._patch( - f"/v1/datasources/{datasource_id}/field", + path_template("/v1/datasources/{datasource_id}/field", datasource_id=datasource_id), body=await async_maybe_transform( { "identifiable_type": identifiable_type, @@ -1079,14 +1151,17 @@ def __init__(self, datasources: DatasourcesResource) -> None: @cached_property def meta(self) -> MetaResourceWithRawResponse: + """数据源管理""" return MetaResourceWithRawResponse(self._datasources.meta) @cached_property def upload_params(self) -> UploadParamsResourceWithRawResponse: + """数据源管理""" return UploadParamsResourceWithRawResponse(self._datasources.upload_params) @cached_property def indexes(self) -> IndexesResourceWithRawResponse: + """索引管理""" return IndexesResourceWithRawResponse(self._datasources.indexes) @@ -1124,14 +1199,17 @@ def __init__(self, datasources: AsyncDatasourcesResource) -> None: @cached_property def meta(self) -> AsyncMetaResourceWithRawResponse: + """数据源管理""" return AsyncMetaResourceWithRawResponse(self._datasources.meta) @cached_property def upload_params(self) -> AsyncUploadParamsResourceWithRawResponse: + """数据源管理""" return AsyncUploadParamsResourceWithRawResponse(self._datasources.upload_params) @cached_property def indexes(self) -> AsyncIndexesResourceWithRawResponse: + """索引管理""" return AsyncIndexesResourceWithRawResponse(self._datasources.indexes) @@ -1169,14 +1247,17 @@ def __init__(self, datasources: DatasourcesResource) -> None: @cached_property def meta(self) -> MetaResourceWithStreamingResponse: + """数据源管理""" return MetaResourceWithStreamingResponse(self._datasources.meta) @cached_property def upload_params(self) -> UploadParamsResourceWithStreamingResponse: + """数据源管理""" return UploadParamsResourceWithStreamingResponse(self._datasources.upload_params) @cached_property def indexes(self) -> IndexesResourceWithStreamingResponse: + """索引管理""" return IndexesResourceWithStreamingResponse(self._datasources.indexes) @@ -1214,12 +1295,15 @@ def __init__(self, datasources: AsyncDatasourcesResource) -> None: @cached_property def meta(self) -> AsyncMetaResourceWithStreamingResponse: + """数据源管理""" return AsyncMetaResourceWithStreamingResponse(self._datasources.meta) @cached_property def upload_params(self) -> AsyncUploadParamsResourceWithStreamingResponse: + """数据源管理""" return AsyncUploadParamsResourceWithStreamingResponse(self._datasources.upload_params) @cached_property def indexes(self) -> AsyncIndexesResourceWithStreamingResponse: + """索引管理""" return AsyncIndexesResourceWithStreamingResponse(self._datasources.indexes) diff --git a/src/asktable/resources/datasources/indexes.py b/src/asktable/resources/datasources/indexes.py index 3ffd6f4a..3d618757 100644 --- a/src/asktable/resources/datasources/indexes.py +++ b/src/asktable/resources/datasources/indexes.py @@ -4,8 +4,8 @@ import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import maybe_transform, async_maybe_transform +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -23,6 +23,8 @@ class IndexesResource(SyncAPIResource): + """索引管理""" + @cached_property def with_raw_response(self) -> IndexesResourceWithRawResponse: """ @@ -49,13 +51,13 @@ def create( field_name: str, schema_name: str, table_name: str, - async_process: bool | NotGiven = NOT_GIVEN, + async_process: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 创建索引 Args: ds_id: 数据源 ID index: 索引创建参数,包含 @@ -79,7 +81,7 @@ def create( if not ds_id: raise ValueError(f"Expected a non-empty value for `ds_id` but received {ds_id!r}") return self._post( - f"/v1/datasources/{ds_id}/indexes", + path_template("/v1/datasources/{ds_id}/indexes", ds_id=ds_id), body=maybe_transform( { "field_name": field_name, @@ -102,14 +104,14 @@ def list( self, ds_id: str, *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, + page: int | Omit = omit, + size: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Index]: """ 获取数据源的所有索引 Args: ds_id: 数据源 ID Returns: 索引列表,包含索引的完整信 @@ -131,7 +133,7 @@ def list( if not ds_id: raise ValueError(f"Expected a non-empty value for `ds_id` but received {ds_id!r}") return self._get_api_list( - f"/v1/datasources/{ds_id}/indexes", + path_template("/v1/datasources/{ds_id}/indexes", ds_id=ds_id), page=SyncPage[Index], options=make_request_options( extra_headers=extra_headers, @@ -159,7 +161,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 删除索引 Args: ds_id: 数据源 ID index_id: 索引 ID @@ -178,7 +180,7 @@ def delete( if not index_id: raise ValueError(f"Expected a non-empty value for `index_id` but received {index_id!r}") return self._delete( - f"/v1/datasources/{ds_id}/indexes/{index_id}", + path_template("/v1/datasources/{ds_id}/indexes/{index_id}", ds_id=ds_id, index_id=index_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -187,6 +189,8 @@ def delete( class AsyncIndexesResource(AsyncAPIResource): + """索引管理""" + @cached_property def with_raw_response(self) -> AsyncIndexesResourceWithRawResponse: """ @@ -213,13 +217,13 @@ async def create( field_name: str, schema_name: str, table_name: str, - async_process: bool | NotGiven = NOT_GIVEN, + async_process: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 创建索引 Args: ds_id: 数据源 ID index: 索引创建参数,包含 @@ -243,7 +247,7 @@ async def create( if not ds_id: raise ValueError(f"Expected a non-empty value for `ds_id` but received {ds_id!r}") return await self._post( - f"/v1/datasources/{ds_id}/indexes", + path_template("/v1/datasources/{ds_id}/indexes", ds_id=ds_id), body=await async_maybe_transform( { "field_name": field_name, @@ -268,14 +272,14 @@ def list( self, ds_id: str, *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, + page: int | Omit = omit, + size: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Index, AsyncPage[Index]]: """ 获取数据源的所有索引 Args: ds_id: 数据源 ID Returns: 索引列表,包含索引的完整信 @@ -297,7 +301,7 @@ def list( if not ds_id: raise ValueError(f"Expected a non-empty value for `ds_id` but received {ds_id!r}") return self._get_api_list( - f"/v1/datasources/{ds_id}/indexes", + path_template("/v1/datasources/{ds_id}/indexes", ds_id=ds_id), page=AsyncPage[Index], options=make_request_options( extra_headers=extra_headers, @@ -325,7 +329,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 删除索引 Args: ds_id: 数据源 ID index_id: 索引 ID @@ -344,7 +348,7 @@ async def delete( if not index_id: raise ValueError(f"Expected a non-empty value for `index_id` but received {index_id!r}") return await self._delete( - f"/v1/datasources/{ds_id}/indexes/{index_id}", + path_template("/v1/datasources/{ds_id}/indexes/{index_id}", ds_id=ds_id, index_id=index_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/asktable/resources/datasources/meta.py b/src/asktable/resources/datasources/meta.py index 431f1fba..2ec3655e 100644 --- a/src/asktable/resources/datasources/meta.py +++ b/src/asktable/resources/datasources/meta.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import Dict, List, Optional +from typing import Dict, Optional import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import maybe_transform, async_maybe_transform +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -24,6 +24,8 @@ class MetaResource(SyncAPIResource): + """数据源管理""" + @cached_property def with_raw_response(self) -> MetaResourceWithRawResponse: """ @@ -47,23 +49,19 @@ def create( self, datasource_id: str, *, - async_process_meta: bool | NotGiven = NOT_GIVEN, - value_index: bool | NotGiven = NOT_GIVEN, - meta: Optional[meta_create_params.Meta] | NotGiven = NOT_GIVEN, - selected_tables: Optional[Dict[str, List[str]]] | NotGiven = NOT_GIVEN, + async_process_meta: bool | Omit = omit, + value_index: bool | Omit = omit, + meta: Optional[meta_create_params.Meta] | Omit = omit, + selected_tables: Optional[Dict[str, SequenceNotStr[str]]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ - 创建数据源的 meta,如果已经存在,则删除旧的 - - 如果上传了 meta,则使用用户上传的数据创建。 - - 否则从数据源中自动获取。 + 初始化数据源的 meta。不允许覆盖已成功初始化的 meta,需使用 PUT 更新。 Args: extra_headers: Send extra headers @@ -77,7 +75,7 @@ def create( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._post( - f"/v1/datasources/{datasource_id}/meta", + path_template("/v1/datasources/{datasource_id}/meta", datasource_id=datasource_id), body=maybe_transform( { "meta": meta, @@ -110,7 +108,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Meta: """ 从数据源中获取最新的元数据 @@ -127,7 +125,7 @@ def retrieve( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._get( - f"/v1/datasources/{datasource_id}/meta", + path_template("/v1/datasources/{datasource_id}/meta", datasource_id=datasource_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -138,15 +136,15 @@ def update( self, datasource_id: str, *, - async_process_meta: bool | NotGiven = NOT_GIVEN, - meta: Optional[meta_update_params.Meta] | NotGiven = NOT_GIVEN, - selected_tables: Optional[Dict[str, List[str]]] | NotGiven = NOT_GIVEN, + async_process_meta: bool | Omit = omit, + meta: Optional[meta_update_params.Meta] | Omit = omit, + selected_tables: Optional[Dict[str, SequenceNotStr[str]]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 用于更新 DB 类型的数据源的 Meta(增加新表或者删除老表) @@ -163,7 +161,7 @@ def update( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._put( - f"/v1/datasources/{datasource_id}/meta", + path_template("/v1/datasources/{datasource_id}/meta", datasource_id=datasource_id), body=maybe_transform( { "meta": meta, @@ -191,7 +189,7 @@ def annotate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 修改数据 meta 的描述,用来修改表和字段的备注 @@ -208,7 +206,7 @@ def annotate( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return self._patch( - f"/v1/datasources/{datasource_id}/meta", + path_template("/v1/datasources/{datasource_id}/meta", datasource_id=datasource_id), body=maybe_transform({"schemas": schemas}, meta_annotate_params.MetaAnnotateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -218,6 +216,8 @@ def annotate( class AsyncMetaResource(AsyncAPIResource): + """数据源管理""" + @cached_property def with_raw_response(self) -> AsyncMetaResourceWithRawResponse: """ @@ -241,23 +241,19 @@ async def create( self, datasource_id: str, *, - async_process_meta: bool | NotGiven = NOT_GIVEN, - value_index: bool | NotGiven = NOT_GIVEN, - meta: Optional[meta_create_params.Meta] | NotGiven = NOT_GIVEN, - selected_tables: Optional[Dict[str, List[str]]] | NotGiven = NOT_GIVEN, + async_process_meta: bool | Omit = omit, + value_index: bool | Omit = omit, + meta: Optional[meta_create_params.Meta] | Omit = omit, + selected_tables: Optional[Dict[str, SequenceNotStr[str]]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ - 创建数据源的 meta,如果已经存在,则删除旧的 - - 如果上传了 meta,则使用用户上传的数据创建。 - - 否则从数据源中自动获取。 + 初始化数据源的 meta。不允许覆盖已成功初始化的 meta,需使用 PUT 更新。 Args: extra_headers: Send extra headers @@ -271,7 +267,7 @@ async def create( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._post( - f"/v1/datasources/{datasource_id}/meta", + path_template("/v1/datasources/{datasource_id}/meta", datasource_id=datasource_id), body=await async_maybe_transform( { "meta": meta, @@ -304,7 +300,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Meta: """ 从数据源中获取最新的元数据 @@ -321,7 +317,7 @@ async def retrieve( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._get( - f"/v1/datasources/{datasource_id}/meta", + path_template("/v1/datasources/{datasource_id}/meta", datasource_id=datasource_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -332,15 +328,15 @@ async def update( self, datasource_id: str, *, - async_process_meta: bool | NotGiven = NOT_GIVEN, - meta: Optional[meta_update_params.Meta] | NotGiven = NOT_GIVEN, - selected_tables: Optional[Dict[str, List[str]]] | NotGiven = NOT_GIVEN, + async_process_meta: bool | Omit = omit, + meta: Optional[meta_update_params.Meta] | Omit = omit, + selected_tables: Optional[Dict[str, SequenceNotStr[str]]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 用于更新 DB 类型的数据源的 Meta(增加新表或者删除老表) @@ -357,7 +353,7 @@ async def update( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._put( - f"/v1/datasources/{datasource_id}/meta", + path_template("/v1/datasources/{datasource_id}/meta", datasource_id=datasource_id), body=await async_maybe_transform( { "meta": meta, @@ -387,7 +383,7 @@ async def annotate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ 修改数据 meta 的描述,用来修改表和字段的备注 @@ -404,7 +400,7 @@ async def annotate( if not datasource_id: raise ValueError(f"Expected a non-empty value for `datasource_id` but received {datasource_id!r}") return await self._patch( - f"/v1/datasources/{datasource_id}/meta", + path_template("/v1/datasources/{datasource_id}/meta", datasource_id=datasource_id), body=await async_maybe_transform({"schemas": schemas}, meta_annotate_params.MetaAnnotateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/asktable/resources/datasources/upload_params.py b/src/asktable/resources/datasources/upload_params.py index 01578571..7cea2f29 100644 --- a/src/asktable/resources/datasources/upload_params.py +++ b/src/asktable/resources/datasources/upload_params.py @@ -6,7 +6,7 @@ import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -18,11 +18,14 @@ ) from ..._base_client import make_request_options from ...types.datasources import upload_param_create_params +from ...types.datasources.upload_param_create_response import UploadParamCreateResponse __all__ = ["UploadParamsResource", "AsyncUploadParamsResource"] class UploadParamsResource(SyncAPIResource): + """数据源管理""" + @cached_property def with_raw_response(self) -> UploadParamsResourceWithRawResponse: """ @@ -45,15 +48,15 @@ def with_streaming_response(self) -> UploadParamsResourceWithStreamingResponse: def create( self, *, - expiration: Optional[int] | NotGiven = NOT_GIVEN, - file_max_size: Optional[int] | NotGiven = NOT_GIVEN, + expiration: Optional[int] | Omit = omit, + file_max_size: Optional[int] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UploadParamCreateResponse: """ 获取 OSS 签名参数 @@ -82,11 +85,13 @@ def create( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=UploadParamCreateResponse, ) class AsyncUploadParamsResource(AsyncAPIResource): + """数据源管理""" + @cached_property def with_raw_response(self) -> AsyncUploadParamsResourceWithRawResponse: """ @@ -109,15 +114,15 @@ def with_streaming_response(self) -> AsyncUploadParamsResourceWithStreamingRespo async def create( self, *, - expiration: Optional[int] | NotGiven = NOT_GIVEN, - file_max_size: Optional[int] | NotGiven = NOT_GIVEN, + expiration: Optional[int] | Omit = omit, + file_max_size: Optional[int] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> UploadParamCreateResponse: """ 获取 OSS 签名参数 @@ -146,7 +151,7 @@ async def create( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=UploadParamCreateResponse, ) diff --git a/src/asktable/resources/files.py b/src/asktable/resources/files.py index 6673a7bf..9c2262d6 100644 --- a/src/asktable/resources/files.py +++ b/src/asktable/resources/files.py @@ -4,7 +4,8 @@ import httpx -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Query, Headers, NotGiven, not_given +from .._utils import path_template from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -19,6 +20,8 @@ class FilesResource(SyncAPIResource): + """数据源管理""" + @cached_property def with_raw_response(self) -> FilesResourceWithRawResponse: """ @@ -47,10 +50,10 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ - 获取文件 + 下载文件 Args: extra_headers: Send extra headers @@ -64,7 +67,7 @@ def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._get( - f"/v1/files/{file_id}", + path_template("/v1/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -73,6 +76,8 @@ def retrieve( class AsyncFilesResource(AsyncAPIResource): + """数据源管理""" + @cached_property def with_raw_response(self) -> AsyncFilesResourceWithRawResponse: """ @@ -101,10 +106,10 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ - 获取文件 + 下载文件 Args: extra_headers: Send extra headers @@ -118,7 +123,7 @@ async def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._get( - f"/v1/files/{file_id}", + path_template("/v1/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/asktable/resources/integration.py b/src/asktable/resources/integration.py index e82d2672..59097b63 100644 --- a/src/asktable/resources/integration.py +++ b/src/asktable/resources/integration.py @@ -6,8 +6,8 @@ import httpx -from ..types import integration_excel_csv_ask_params, integration_create_excel_ds_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..types import integration_excel_csv_ask_params +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -18,13 +18,13 @@ async_to_streamed_response_wrapper, ) from .._base_client import make_request_options -from ..types.datasource import Datasource -from ..types.file_ask_response import FileAskResponse __all__ = ["IntegrationResource", "AsyncIntegrationResource"] class IntegrationResource(SyncAPIResource): + """与第三方平台集成""" + @cached_property def with_raw_response(self) -> IntegrationResourceWithRawResponse: """ @@ -44,63 +44,21 @@ def with_streaming_response(self) -> IntegrationResourceWithStreamingResponse: """ return IntegrationResourceWithStreamingResponse(self) - def create_excel_ds( - self, - *, - file_url: str, - value_index: bool | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Datasource: - """ - 通过 Excel/CSV 文件 URL 创建数据源 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/integration/create_excel_ds", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "file_url": file_url, - "value_index": value_index, - }, - integration_create_excel_ds_params.IntegrationCreateExcelDsParams, - ), - ), - cast_to=Datasource, - ) - def excel_csv_ask( self, *, file_url: str, question: str, - with_json: Optional[bool] | NotGiven = NOT_GIVEN, + with_json: Optional[bool] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FileAskResponse: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: """ - 通过 Excel/CSV 文件 URL 添加数据并提问 + Add Excel And Ask Args: file_url: 文件 URL(支持 Excel/CSV) @@ -130,11 +88,13 @@ def excel_csv_ask( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=FileAskResponse, + cast_to=object, ) class AsyncIntegrationResource(AsyncAPIResource): + """与第三方平台集成""" + @cached_property def with_raw_response(self) -> AsyncIntegrationResourceWithRawResponse: """ @@ -154,63 +114,21 @@ def with_streaming_response(self) -> AsyncIntegrationResourceWithStreamingRespon """ return AsyncIntegrationResourceWithStreamingResponse(self) - async def create_excel_ds( - self, - *, - file_url: str, - value_index: bool | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Datasource: - """ - 通过 Excel/CSV 文件 URL 创建数据源 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/integration/create_excel_ds", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "file_url": file_url, - "value_index": value_index, - }, - integration_create_excel_ds_params.IntegrationCreateExcelDsParams, - ), - ), - cast_to=Datasource, - ) - async def excel_csv_ask( self, *, file_url: str, question: str, - with_json: Optional[bool] | NotGiven = NOT_GIVEN, + with_json: Optional[bool] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> FileAskResponse: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: """ - 通过 Excel/CSV 文件 URL 添加数据并提问 + Add Excel And Ask Args: file_url: 文件 URL(支持 Excel/CSV) @@ -240,7 +158,7 @@ async def excel_csv_ask( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=FileAskResponse, + cast_to=object, ) @@ -248,9 +166,6 @@ class IntegrationResourceWithRawResponse: def __init__(self, integration: IntegrationResource) -> None: self._integration = integration - self.create_excel_ds = to_raw_response_wrapper( - integration.create_excel_ds, - ) self.excel_csv_ask = to_raw_response_wrapper( integration.excel_csv_ask, ) @@ -260,9 +175,6 @@ class AsyncIntegrationResourceWithRawResponse: def __init__(self, integration: AsyncIntegrationResource) -> None: self._integration = integration - self.create_excel_ds = async_to_raw_response_wrapper( - integration.create_excel_ds, - ) self.excel_csv_ask = async_to_raw_response_wrapper( integration.excel_csv_ask, ) @@ -272,9 +184,6 @@ class IntegrationResourceWithStreamingResponse: def __init__(self, integration: IntegrationResource) -> None: self._integration = integration - self.create_excel_ds = to_streamed_response_wrapper( - integration.create_excel_ds, - ) self.excel_csv_ask = to_streamed_response_wrapper( integration.excel_csv_ask, ) @@ -284,9 +193,6 @@ class AsyncIntegrationResourceWithStreamingResponse: def __init__(self, integration: AsyncIntegrationResource) -> None: self._integration = integration - self.create_excel_ds = async_to_streamed_response_wrapper( - integration.create_excel_ds, - ) self.excel_csv_ask = async_to_streamed_response_wrapper( integration.excel_csv_ask, ) diff --git a/src/asktable/resources/policies.py b/src/asktable/resources/policies.py deleted file mode 100644 index fc27f2c4..00000000 --- a/src/asktable/resources/policies.py +++ /dev/null @@ -1,589 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from typing_extensions import Literal - -import httpx - -from ..types import policy_list_params, policy_create_params, policy_update_params -from .._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..pagination import SyncPage, AsyncPage -from .._base_client import AsyncPaginator, make_request_options -from ..types.shared.policy import Policy - -__all__ = ["PoliciesResource", "AsyncPoliciesResource"] - - -class PoliciesResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> PoliciesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return PoliciesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PoliciesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return PoliciesResourceWithStreamingResponse(self) - - def create( - self, - *, - dataset_config: policy_create_params.DatasetConfig, - name: str, - permission: Literal["allow", "deny"], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Policy: - """ - 定义一个新的策略 - - Args: - dataset_config: 数据集配置 - - name: 名称 - - permission: 权限 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/policies", - body=maybe_transform( - { - "dataset_config": dataset_config, - "name": name, - "permission": permission, - }, - policy_create_params.PolicyCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Policy, - ) - - def retrieve( - self, - policy_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Policy: - """ - 获取某个策略 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not policy_id: - raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") - return self._get( - f"/v1/policies/{policy_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Policy, - ) - - def update( - self, - policy_id: str, - *, - dataset_config: Optional[policy_update_params.DatasetConfig] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - permission: Optional[Literal["allow", "deny"]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Policy: - """ - 更新某个策略 - - Args: - dataset_config: 数据集配置 - - name: 名称 - - permission: 权限 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not policy_id: - raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") - return self._patch( - f"/v1/policies/{policy_id}", - body=maybe_transform( - { - "dataset_config": dataset_config, - "name": name, - "permission": permission, - }, - policy_update_params.PolicyUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Policy, - ) - - def list( - self, - *, - name: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - policy_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[Policy]: - """ - 查询所有策略 - - Args: - name: 策略名称 - - page: Page number - - policy_ids: 策略 ID 列表 - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/policies", - page=SyncPage[Policy], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "name": name, - "page": page, - "policy_ids": policy_ids, - "size": size, - }, - policy_list_params.PolicyListParams, - ), - ), - model=Policy, - ) - - def delete( - self, - policy_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - 删除某个策略 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not policy_id: - raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/v1/policies/{policy_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncPoliciesResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncPoliciesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncPoliciesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPoliciesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncPoliciesResourceWithStreamingResponse(self) - - async def create( - self, - *, - dataset_config: policy_create_params.DatasetConfig, - name: str, - permission: Literal["allow", "deny"], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Policy: - """ - 定义一个新的策略 - - Args: - dataset_config: 数据集配置 - - name: 名称 - - permission: 权限 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/policies", - body=await async_maybe_transform( - { - "dataset_config": dataset_config, - "name": name, - "permission": permission, - }, - policy_create_params.PolicyCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Policy, - ) - - async def retrieve( - self, - policy_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Policy: - """ - 获取某个策略 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not policy_id: - raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") - return await self._get( - f"/v1/policies/{policy_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Policy, - ) - - async def update( - self, - policy_id: str, - *, - dataset_config: Optional[policy_update_params.DatasetConfig] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - permission: Optional[Literal["allow", "deny"]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Policy: - """ - 更新某个策略 - - Args: - dataset_config: 数据集配置 - - name: 名称 - - permission: 权限 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not policy_id: - raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") - return await self._patch( - f"/v1/policies/{policy_id}", - body=await async_maybe_transform( - { - "dataset_config": dataset_config, - "name": name, - "permission": permission, - }, - policy_update_params.PolicyUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Policy, - ) - - def list( - self, - *, - name: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - policy_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[Policy, AsyncPage[Policy]]: - """ - 查询所有策略 - - Args: - name: 策略名称 - - page: Page number - - policy_ids: 策略 ID 列表 - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/policies", - page=AsyncPage[Policy], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "name": name, - "page": page, - "policy_ids": policy_ids, - "size": size, - }, - policy_list_params.PolicyListParams, - ), - ), - model=Policy, - ) - - async def delete( - self, - policy_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - 删除某个策略 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not policy_id: - raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/v1/policies/{policy_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class PoliciesResourceWithRawResponse: - def __init__(self, policies: PoliciesResource) -> None: - self._policies = policies - - self.create = to_raw_response_wrapper( - policies.create, - ) - self.retrieve = to_raw_response_wrapper( - policies.retrieve, - ) - self.update = to_raw_response_wrapper( - policies.update, - ) - self.list = to_raw_response_wrapper( - policies.list, - ) - self.delete = to_raw_response_wrapper( - policies.delete, - ) - - -class AsyncPoliciesResourceWithRawResponse: - def __init__(self, policies: AsyncPoliciesResource) -> None: - self._policies = policies - - self.create = async_to_raw_response_wrapper( - policies.create, - ) - self.retrieve = async_to_raw_response_wrapper( - policies.retrieve, - ) - self.update = async_to_raw_response_wrapper( - policies.update, - ) - self.list = async_to_raw_response_wrapper( - policies.list, - ) - self.delete = async_to_raw_response_wrapper( - policies.delete, - ) - - -class PoliciesResourceWithStreamingResponse: - def __init__(self, policies: PoliciesResource) -> None: - self._policies = policies - - self.create = to_streamed_response_wrapper( - policies.create, - ) - self.retrieve = to_streamed_response_wrapper( - policies.retrieve, - ) - self.update = to_streamed_response_wrapper( - policies.update, - ) - self.list = to_streamed_response_wrapper( - policies.list, - ) - self.delete = to_streamed_response_wrapper( - policies.delete, - ) - - -class AsyncPoliciesResourceWithStreamingResponse: - def __init__(self, policies: AsyncPoliciesResource) -> None: - self._policies = policies - - self.create = async_to_streamed_response_wrapper( - policies.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - policies.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - policies.update, - ) - self.list = async_to_streamed_response_wrapper( - policies.list, - ) - self.delete = async_to_streamed_response_wrapper( - policies.delete, - ) diff --git a/src/asktable/resources/polish.py b/src/asktable/resources/polish.py index 23df7f15..5a51a4c6 100644 --- a/src/asktable/resources/polish.py +++ b/src/asktable/resources/polish.py @@ -7,7 +7,7 @@ import httpx from ..types import polish_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -24,6 +24,8 @@ class PolishResource(SyncAPIResource): + """润色""" + @cached_property def with_raw_response(self) -> PolishResourceWithRawResponse: """ @@ -48,13 +50,13 @@ def create( *, max_word_count: int, user_desc: str, - polish_mode: Literal[0] | NotGiven = NOT_GIVEN, + polish_mode: Literal[0] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PolishCreateResponse: """ Polish Table Desc @@ -92,6 +94,8 @@ def create( class AsyncPolishResource(AsyncAPIResource): + """润色""" + @cached_property def with_raw_response(self) -> AsyncPolishResourceWithRawResponse: """ @@ -116,13 +120,13 @@ async def create( *, max_word_count: int, user_desc: str, - polish_mode: Literal[0] | NotGiven = NOT_GIVEN, + polish_mode: Literal[0] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PolishCreateResponse: """ Polish Table Desc diff --git a/src/asktable/resources/preferences.py b/src/asktable/resources/preferences.py deleted file mode 100644 index a96452be..00000000 --- a/src/asktable/resources/preferences.py +++ /dev/null @@ -1,387 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional - -import httpx - -from ..types import preference_create_params, preference_update_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from .._base_client import make_request_options -from ..types.preference_create_response import PreferenceCreateResponse -from ..types.preference_update_response import PreferenceUpdateResponse -from ..types.preference_retrieve_response import PreferenceRetrieveResponse - -__all__ = ["PreferencesResource", "AsyncPreferencesResource"] - - -class PreferencesResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> PreferencesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return PreferencesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PreferencesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return PreferencesResourceWithStreamingResponse(self) - - def create( - self, - *, - general_preference: str, - sql_preference: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> PreferenceCreateResponse: - """ - 创建偏好设置 - - Args: - general_preference: 通用偏好设置内容 - - sql_preference: SQL 偏好设置内容 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/preference", - body=maybe_transform( - { - "general_preference": general_preference, - "sql_preference": sql_preference, - }, - preference_create_params.PreferenceCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PreferenceCreateResponse, - ) - - def retrieve( - self, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> PreferenceRetrieveResponse: - """获取偏好设置""" - return self._get( - "/v1/preference", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PreferenceRetrieveResponse, - ) - - def update( - self, - *, - general_preference: Optional[str] | NotGiven = NOT_GIVEN, - sql_preference: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> PreferenceUpdateResponse: - """ - 更新偏好设置 - - Args: - general_preference: 通用偏好设置内容 - - sql_preference: SQL 偏好设置内容 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._patch( - "/v1/preference", - body=maybe_transform( - { - "general_preference": general_preference, - "sql_preference": sql_preference, - }, - preference_update_params.PreferenceUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PreferenceUpdateResponse, - ) - - def delete( - self, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """删除偏好设置""" - return self._delete( - "/v1/preference", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - -class AsyncPreferencesResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncPreferencesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncPreferencesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPreferencesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncPreferencesResourceWithStreamingResponse(self) - - async def create( - self, - *, - general_preference: str, - sql_preference: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> PreferenceCreateResponse: - """ - 创建偏好设置 - - Args: - general_preference: 通用偏好设置内容 - - sql_preference: SQL 偏好设置内容 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/preference", - body=await async_maybe_transform( - { - "general_preference": general_preference, - "sql_preference": sql_preference, - }, - preference_create_params.PreferenceCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PreferenceCreateResponse, - ) - - async def retrieve( - self, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> PreferenceRetrieveResponse: - """获取偏好设置""" - return await self._get( - "/v1/preference", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PreferenceRetrieveResponse, - ) - - async def update( - self, - *, - general_preference: Optional[str] | NotGiven = NOT_GIVEN, - sql_preference: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> PreferenceUpdateResponse: - """ - 更新偏好设置 - - Args: - general_preference: 通用偏好设置内容 - - sql_preference: SQL 偏好设置内容 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._patch( - "/v1/preference", - body=await async_maybe_transform( - { - "general_preference": general_preference, - "sql_preference": sql_preference, - }, - preference_update_params.PreferenceUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PreferenceUpdateResponse, - ) - - async def delete( - self, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """删除偏好设置""" - return await self._delete( - "/v1/preference", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - -class PreferencesResourceWithRawResponse: - def __init__(self, preferences: PreferencesResource) -> None: - self._preferences = preferences - - self.create = to_raw_response_wrapper( - preferences.create, - ) - self.retrieve = to_raw_response_wrapper( - preferences.retrieve, - ) - self.update = to_raw_response_wrapper( - preferences.update, - ) - self.delete = to_raw_response_wrapper( - preferences.delete, - ) - - -class AsyncPreferencesResourceWithRawResponse: - def __init__(self, preferences: AsyncPreferencesResource) -> None: - self._preferences = preferences - - self.create = async_to_raw_response_wrapper( - preferences.create, - ) - self.retrieve = async_to_raw_response_wrapper( - preferences.retrieve, - ) - self.update = async_to_raw_response_wrapper( - preferences.update, - ) - self.delete = async_to_raw_response_wrapper( - preferences.delete, - ) - - -class PreferencesResourceWithStreamingResponse: - def __init__(self, preferences: PreferencesResource) -> None: - self._preferences = preferences - - self.create = to_streamed_response_wrapper( - preferences.create, - ) - self.retrieve = to_streamed_response_wrapper( - preferences.retrieve, - ) - self.update = to_streamed_response_wrapper( - preferences.update, - ) - self.delete = to_streamed_response_wrapper( - preferences.delete, - ) - - -class AsyncPreferencesResourceWithStreamingResponse: - def __init__(self, preferences: AsyncPreferencesResource) -> None: - self._preferences = preferences - - self.create = async_to_streamed_response_wrapper( - preferences.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - preferences.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - preferences.update, - ) - self.delete = async_to_streamed_response_wrapper( - preferences.delete, - ) diff --git a/src/asktable/resources/project.py b/src/asktable/resources/project.py index 5624ab32..920f2d1c 100644 --- a/src/asktable/resources/project.py +++ b/src/asktable/resources/project.py @@ -7,7 +7,7 @@ import httpx from ..types import project_update_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -25,6 +25,8 @@ class ProjectResource(SyncAPIResource): + """我的项目""" + @cached_property def with_raw_response(self) -> ProjectResourceWithRawResponse: """ @@ -52,7 +54,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """Get My Project""" return self._get( @@ -66,14 +68,14 @@ def retrieve( def update( self, *, - llm_model_group: Optional[str] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + llm_model_group: Optional[str] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Update My Project @@ -114,7 +116,7 @@ def list_model_groups( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProjectListModelGroupsResponse: """Get Llm Model Groups""" return self._get( @@ -127,6 +129,8 @@ def list_model_groups( class AsyncProjectResource(AsyncAPIResource): + """我的项目""" + @cached_property def with_raw_response(self) -> AsyncProjectResourceWithRawResponse: """ @@ -154,7 +158,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """Get My Project""" return await self._get( @@ -168,14 +172,14 @@ async def retrieve( async def update( self, *, - llm_model_group: Optional[str] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + llm_model_group: Optional[str] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Update My Project @@ -216,7 +220,7 @@ async def list_model_groups( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProjectListModelGroupsResponse: """Get Llm Model Groups""" return await self._get( diff --git a/src/asktable/resources/roles.py b/src/asktable/resources/roles.py deleted file mode 100644 index c05f9a91..00000000 --- a/src/asktable/resources/roles.py +++ /dev/null @@ -1,759 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional - -import httpx - -from ..types import role_list_params, role_create_params, role_update_params, role_get_variables_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..pagination import SyncPage, AsyncPage -from ..types.role import Role -from .._base_client import AsyncPaginator, make_request_options -from ..types.role_get_polices_response import RoleGetPolicesResponse - -__all__ = ["RolesResource", "AsyncRolesResource"] - - -class RolesResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> RolesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return RolesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RolesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return RolesResourceWithStreamingResponse(self) - - def create( - self, - *, - name: str, - policy_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Role: - """ - 创建一个新的角色 - - Args: - name: 名称 - - policy_ids: 策略列表。注意:如果为空或者不传则不绑定策略 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/roles", - body=maybe_transform( - { - "name": name, - "policy_ids": policy_ids, - }, - role_create_params.RoleCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Role, - ) - - def retrieve( - self, - role_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Role: - """ - 获取某个角色 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return self._get( - f"/v1/roles/{role_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Role, - ) - - def update( - self, - role_id: str, - *, - name: Optional[str] | NotGiven = NOT_GIVEN, - policy_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Role: - """ - 更新某个角色 - - Args: - name: 名称 - - policy_ids: 策略列表。注意:如果为空或者不传则不绑定策略 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return self._patch( - f"/v1/roles/{role_id}", - body=maybe_transform( - { - "name": name, - "policy_ids": policy_ids, - }, - role_update_params.RoleUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Role, - ) - - def list( - self, - *, - name: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - role_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[Role]: - """ - 查询所有的角色 - - Args: - name: 角色名称 - - page: Page number - - role_ids: 角色 ID 列表 - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/roles", - page=SyncPage[Role], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "name": name, - "page": page, - "role_ids": role_ids, - "size": size, - }, - role_list_params.RoleListParams, - ), - ), - model=Role, - ) - - def delete( - self, - role_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 删除某个角色 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return self._delete( - f"/v1/roles/{role_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - def get_polices( - self, - role_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> RoleGetPolicesResponse: - """ - 查询某个角色的所有策略 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return self._get( - f"/v1/roles/{role_id}/policies", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RoleGetPolicesResponse, - ) - - def get_variables( - self, - role_id: str, - *, - bot_id: Optional[str] | NotGiven = NOT_GIVEN, - datasource_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 查询某个角色的所有变量 - - Args: - bot_id: Bot ID - - datasource_ids: 数据源 ID 列表 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return self._get( - f"/v1/roles/{role_id}/variables", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "bot_id": bot_id, - "datasource_ids": datasource_ids, - }, - role_get_variables_params.RoleGetVariablesParams, - ), - ), - cast_to=object, - ) - - -class AsyncRolesResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncRolesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncRolesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRolesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncRolesResourceWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - policy_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Role: - """ - 创建一个新的角色 - - Args: - name: 名称 - - policy_ids: 策略列表。注意:如果为空或者不传则不绑定策略 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/roles", - body=await async_maybe_transform( - { - "name": name, - "policy_ids": policy_ids, - }, - role_create_params.RoleCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Role, - ) - - async def retrieve( - self, - role_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Role: - """ - 获取某个角色 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return await self._get( - f"/v1/roles/{role_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Role, - ) - - async def update( - self, - role_id: str, - *, - name: Optional[str] | NotGiven = NOT_GIVEN, - policy_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Role: - """ - 更新某个角色 - - Args: - name: 名称 - - policy_ids: 策略列表。注意:如果为空或者不传则不绑定策略 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return await self._patch( - f"/v1/roles/{role_id}", - body=await async_maybe_transform( - { - "name": name, - "policy_ids": policy_ids, - }, - role_update_params.RoleUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Role, - ) - - def list( - self, - *, - name: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - role_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[Role, AsyncPage[Role]]: - """ - 查询所有的角色 - - Args: - name: 角色名称 - - page: Page number - - role_ids: 角色 ID 列表 - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/roles", - page=AsyncPage[Role], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "name": name, - "page": page, - "role_ids": role_ids, - "size": size, - }, - role_list_params.RoleListParams, - ), - ), - model=Role, - ) - - async def delete( - self, - role_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 删除某个角色 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return await self._delete( - f"/v1/roles/{role_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - async def get_polices( - self, - role_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> RoleGetPolicesResponse: - """ - 查询某个角色的所有策略 - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return await self._get( - f"/v1/roles/{role_id}/policies", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RoleGetPolicesResponse, - ) - - async def get_variables( - self, - role_id: str, - *, - bot_id: Optional[str] | NotGiven = NOT_GIVEN, - datasource_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - 查询某个角色的所有变量 - - Args: - bot_id: Bot ID - - datasource_ids: 数据源 ID 列表 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not role_id: - raise ValueError(f"Expected a non-empty value for `role_id` but received {role_id!r}") - return await self._get( - f"/v1/roles/{role_id}/variables", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "bot_id": bot_id, - "datasource_ids": datasource_ids, - }, - role_get_variables_params.RoleGetVariablesParams, - ), - ), - cast_to=object, - ) - - -class RolesResourceWithRawResponse: - def __init__(self, roles: RolesResource) -> None: - self._roles = roles - - self.create = to_raw_response_wrapper( - roles.create, - ) - self.retrieve = to_raw_response_wrapper( - roles.retrieve, - ) - self.update = to_raw_response_wrapper( - roles.update, - ) - self.list = to_raw_response_wrapper( - roles.list, - ) - self.delete = to_raw_response_wrapper( - roles.delete, - ) - self.get_polices = to_raw_response_wrapper( - roles.get_polices, - ) - self.get_variables = to_raw_response_wrapper( - roles.get_variables, - ) - - -class AsyncRolesResourceWithRawResponse: - def __init__(self, roles: AsyncRolesResource) -> None: - self._roles = roles - - self.create = async_to_raw_response_wrapper( - roles.create, - ) - self.retrieve = async_to_raw_response_wrapper( - roles.retrieve, - ) - self.update = async_to_raw_response_wrapper( - roles.update, - ) - self.list = async_to_raw_response_wrapper( - roles.list, - ) - self.delete = async_to_raw_response_wrapper( - roles.delete, - ) - self.get_polices = async_to_raw_response_wrapper( - roles.get_polices, - ) - self.get_variables = async_to_raw_response_wrapper( - roles.get_variables, - ) - - -class RolesResourceWithStreamingResponse: - def __init__(self, roles: RolesResource) -> None: - self._roles = roles - - self.create = to_streamed_response_wrapper( - roles.create, - ) - self.retrieve = to_streamed_response_wrapper( - roles.retrieve, - ) - self.update = to_streamed_response_wrapper( - roles.update, - ) - self.list = to_streamed_response_wrapper( - roles.list, - ) - self.delete = to_streamed_response_wrapper( - roles.delete, - ) - self.get_polices = to_streamed_response_wrapper( - roles.get_polices, - ) - self.get_variables = to_streamed_response_wrapper( - roles.get_variables, - ) - - -class AsyncRolesResourceWithStreamingResponse: - def __init__(self, roles: AsyncRolesResource) -> None: - self._roles = roles - - self.create = async_to_streamed_response_wrapper( - roles.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - roles.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - roles.update, - ) - self.list = async_to_streamed_response_wrapper( - roles.list, - ) - self.delete = async_to_streamed_response_wrapper( - roles.delete, - ) - self.get_polices = async_to_streamed_response_wrapper( - roles.get_polices, - ) - self.get_variables = async_to_streamed_response_wrapper( - roles.get_variables, - ) diff --git a/src/asktable/resources/scores.py b/src/asktable/resources/scores.py index 343a17e8..b0be93e4 100644 --- a/src/asktable/resources/scores.py +++ b/src/asktable/resources/scores.py @@ -5,7 +5,7 @@ import httpx from ..types import score_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Query, Headers, NotGiven, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -16,12 +16,13 @@ async_to_streamed_response_wrapper, ) from .._base_client import make_request_options -from ..types.score_create_response import ScoreCreateResponse __all__ = ["ScoresResource", "AsyncScoresResource"] class ScoresResource(SyncAPIResource): + """评分""" + @cached_property def with_raw_response(self) -> ScoresResourceWithRawResponse: """ @@ -52,18 +53,12 @@ def create( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ScoreCreateResponse: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: """ Score Args: - chat_id: 聊天 ID - - message_id: 消息 ID - - score: 评分 - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -88,11 +83,13 @@ def create( score_create_params.ScoreCreateParams, ), ), - cast_to=ScoreCreateResponse, + cast_to=object, ) class AsyncScoresResource(AsyncAPIResource): + """评分""" + @cached_property def with_raw_response(self) -> AsyncScoresResourceWithRawResponse: """ @@ -123,18 +120,12 @@ async def create( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> ScoreCreateResponse: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> object: """ Score Args: - chat_id: 聊天 ID - - message_id: 消息 ID - - score: 评分 - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -159,7 +150,7 @@ async def create( score_create_params.ScoreCreateParams, ), ), - cast_to=ScoreCreateResponse, + cast_to=object, ) diff --git a/src/asktable/resources/securetunnels.py b/src/asktable/resources/securetunnels.py deleted file mode 100644 index 13476a28..00000000 --- a/src/asktable/resources/securetunnels.py +++ /dev/null @@ -1,664 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional - -import httpx - -from ..types import ( - securetunnel_list_params, - securetunnel_create_params, - securetunnel_update_params, - securetunnel_list_links_params, -) -from .._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..pagination import SyncPage, AsyncPage -from .._base_client import AsyncPaginator, make_request_options -from ..types.secure_tunnel import SecureTunnel -from ..types.securetunnel_list_links_response import SecuretunnelListLinksResponse - -__all__ = ["SecuretunnelsResource", "AsyncSecuretunnelsResource"] - - -class SecuretunnelsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> SecuretunnelsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return SecuretunnelsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> SecuretunnelsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return SecuretunnelsResourceWithStreamingResponse(self) - - def create( - self, - *, - name: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SecureTunnel: - """ - 创建安全隧道 - - Args: - name: SecureTunnel 名称,不超过 20 个字符 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/securetunnels", - body=maybe_transform({"name": name}, securetunnel_create_params.SecuretunnelCreateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SecureTunnel, - ) - - def retrieve( - self, - securetunnel_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SecureTunnel: - """ - 获取某个 ATST - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not securetunnel_id: - raise ValueError(f"Expected a non-empty value for `securetunnel_id` but received {securetunnel_id!r}") - return self._get( - f"/v1/securetunnels/{securetunnel_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SecureTunnel, - ) - - def update( - self, - securetunnel_id: str, - *, - client_info: Optional[object] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - unique_key: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SecureTunnel: - """ - 更新某个 ATST - - Args: - client_info: 客户端信息 - - name: SecureTunnel 名称,不超过 20 个字符 - - unique_key: 唯一标识,用于更新客户端信息(容器 ID) - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not securetunnel_id: - raise ValueError(f"Expected a non-empty value for `securetunnel_id` but received {securetunnel_id!r}") - return self._patch( - f"/v1/securetunnels/{securetunnel_id}", - body=maybe_transform( - { - "client_info": client_info, - "name": name, - "unique_key": unique_key, - }, - securetunnel_update_params.SecuretunnelUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SecureTunnel, - ) - - def list( - self, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[SecureTunnel]: - """ - 查询安全隧道列表 - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/securetunnels", - page=SyncPage[SecureTunnel], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - securetunnel_list_params.SecuretunnelListParams, - ), - ), - model=SecureTunnel, - ) - - def delete( - self, - securetunnel_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - 删除某个 ATST - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not securetunnel_id: - raise ValueError(f"Expected a non-empty value for `securetunnel_id` but received {securetunnel_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/v1/securetunnels/{securetunnel_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def list_links( - self, - securetunnel_id: str, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[SecuretunnelListLinksResponse]: - """ - 查询安全隧道的所有 Link - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not securetunnel_id: - raise ValueError(f"Expected a non-empty value for `securetunnel_id` but received {securetunnel_id!r}") - return self._get_api_list( - f"/v1/securetunnels/{securetunnel_id}/links", - page=SyncPage[SecuretunnelListLinksResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - securetunnel_list_links_params.SecuretunnelListLinksParams, - ), - ), - model=SecuretunnelListLinksResponse, - ) - - -class AsyncSecuretunnelsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncSecuretunnelsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncSecuretunnelsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncSecuretunnelsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncSecuretunnelsResourceWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SecureTunnel: - """ - 创建安全隧道 - - Args: - name: SecureTunnel 名称,不超过 20 个字符 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/securetunnels", - body=await async_maybe_transform({"name": name}, securetunnel_create_params.SecuretunnelCreateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SecureTunnel, - ) - - async def retrieve( - self, - securetunnel_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SecureTunnel: - """ - 获取某个 ATST - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not securetunnel_id: - raise ValueError(f"Expected a non-empty value for `securetunnel_id` but received {securetunnel_id!r}") - return await self._get( - f"/v1/securetunnels/{securetunnel_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SecureTunnel, - ) - - async def update( - self, - securetunnel_id: str, - *, - client_info: Optional[object] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - unique_key: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SecureTunnel: - """ - 更新某个 ATST - - Args: - client_info: 客户端信息 - - name: SecureTunnel 名称,不超过 20 个字符 - - unique_key: 唯一标识,用于更新客户端信息(容器 ID) - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not securetunnel_id: - raise ValueError(f"Expected a non-empty value for `securetunnel_id` but received {securetunnel_id!r}") - return await self._patch( - f"/v1/securetunnels/{securetunnel_id}", - body=await async_maybe_transform( - { - "client_info": client_info, - "name": name, - "unique_key": unique_key, - }, - securetunnel_update_params.SecuretunnelUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SecureTunnel, - ) - - def list( - self, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[SecureTunnel, AsyncPage[SecureTunnel]]: - """ - 查询安全隧道列表 - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/securetunnels", - page=AsyncPage[SecureTunnel], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - securetunnel_list_params.SecuretunnelListParams, - ), - ), - model=SecureTunnel, - ) - - async def delete( - self, - securetunnel_id: str, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> None: - """ - 删除某个 ATST - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not securetunnel_id: - raise ValueError(f"Expected a non-empty value for `securetunnel_id` but received {securetunnel_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/v1/securetunnels/{securetunnel_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def list_links( - self, - securetunnel_id: str, - *, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[SecuretunnelListLinksResponse, AsyncPage[SecuretunnelListLinksResponse]]: - """ - 查询安全隧道的所有 Link - - Args: - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not securetunnel_id: - raise ValueError(f"Expected a non-empty value for `securetunnel_id` but received {securetunnel_id!r}") - return self._get_api_list( - f"/v1/securetunnels/{securetunnel_id}/links", - page=AsyncPage[SecuretunnelListLinksResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "size": size, - }, - securetunnel_list_links_params.SecuretunnelListLinksParams, - ), - ), - model=SecuretunnelListLinksResponse, - ) - - -class SecuretunnelsResourceWithRawResponse: - def __init__(self, securetunnels: SecuretunnelsResource) -> None: - self._securetunnels = securetunnels - - self.create = to_raw_response_wrapper( - securetunnels.create, - ) - self.retrieve = to_raw_response_wrapper( - securetunnels.retrieve, - ) - self.update = to_raw_response_wrapper( - securetunnels.update, - ) - self.list = to_raw_response_wrapper( - securetunnels.list, - ) - self.delete = to_raw_response_wrapper( - securetunnels.delete, - ) - self.list_links = to_raw_response_wrapper( - securetunnels.list_links, - ) - - -class AsyncSecuretunnelsResourceWithRawResponse: - def __init__(self, securetunnels: AsyncSecuretunnelsResource) -> None: - self._securetunnels = securetunnels - - self.create = async_to_raw_response_wrapper( - securetunnels.create, - ) - self.retrieve = async_to_raw_response_wrapper( - securetunnels.retrieve, - ) - self.update = async_to_raw_response_wrapper( - securetunnels.update, - ) - self.list = async_to_raw_response_wrapper( - securetunnels.list, - ) - self.delete = async_to_raw_response_wrapper( - securetunnels.delete, - ) - self.list_links = async_to_raw_response_wrapper( - securetunnels.list_links, - ) - - -class SecuretunnelsResourceWithStreamingResponse: - def __init__(self, securetunnels: SecuretunnelsResource) -> None: - self._securetunnels = securetunnels - - self.create = to_streamed_response_wrapper( - securetunnels.create, - ) - self.retrieve = to_streamed_response_wrapper( - securetunnels.retrieve, - ) - self.update = to_streamed_response_wrapper( - securetunnels.update, - ) - self.list = to_streamed_response_wrapper( - securetunnels.list, - ) - self.delete = to_streamed_response_wrapper( - securetunnels.delete, - ) - self.list_links = to_streamed_response_wrapper( - securetunnels.list_links, - ) - - -class AsyncSecuretunnelsResourceWithStreamingResponse: - def __init__(self, securetunnels: AsyncSecuretunnelsResource) -> None: - self._securetunnels = securetunnels - - self.create = async_to_streamed_response_wrapper( - securetunnels.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - securetunnels.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - securetunnels.update, - ) - self.list = async_to_streamed_response_wrapper( - securetunnels.list, - ) - self.delete = async_to_streamed_response_wrapper( - securetunnels.delete, - ) - self.list_links = async_to_streamed_response_wrapper( - securetunnels.list_links, - ) diff --git a/src/asktable/resources/sqls.py b/src/asktable/resources/sqls.py deleted file mode 100644 index fc871c84..00000000 --- a/src/asktable/resources/sqls.py +++ /dev/null @@ -1,328 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional - -import httpx - -from ..types import sql_list_params, sql_create_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..pagination import SyncPage, AsyncPage -from .._base_client import AsyncPaginator, make_request_options -from ..types.query_response import QueryResponse - -__all__ = ["SqlsResource", "AsyncSqlsResource"] - - -class SqlsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> SqlsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return SqlsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> SqlsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return SqlsResourceWithStreamingResponse(self) - - def create( - self, - *, - datasource_id: str, - question: str, - parameterize: bool | NotGiven = NOT_GIVEN, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[object] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> QueryResponse: - """ - 发起生成 sql 的请求 - - Args: - datasource_id: 数据源 ID - - question: 查询语句 - - parameterize: 是否将参数分开传递 - - role_id: 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/single-turn/q2s", - body=maybe_transform( - { - "datasource_id": datasource_id, - "question": question, - "parameterize": parameterize, - "role_id": role_id, - "role_variables": role_variables, - }, - sql_create_params.SqlCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=QueryResponse, - ) - - def list( - self, - *, - datasource_id: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[QueryResponse]: - """ - 获取所有的 Q2S 记录 - - Args: - datasource_id: 数据源 ID - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/single-turn/q2s", - page=SyncPage[QueryResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "datasource_id": datasource_id, - "page": page, - "size": size, - }, - sql_list_params.SqlListParams, - ), - ), - model=QueryResponse, - ) - - -class AsyncSqlsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncSqlsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncSqlsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncSqlsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncSqlsResourceWithStreamingResponse(self) - - async def create( - self, - *, - datasource_id: str, - question: str, - parameterize: bool | NotGiven = NOT_GIVEN, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - role_variables: Optional[object] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> QueryResponse: - """ - 发起生成 sql 的请求 - - Args: - datasource_id: 数据源 ID - - question: 查询语句 - - parameterize: 是否将参数分开传递 - - role_id: 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - - role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/single-turn/q2s", - body=await async_maybe_transform( - { - "datasource_id": datasource_id, - "question": question, - "parameterize": parameterize, - "role_id": role_id, - "role_variables": role_variables, - }, - sql_create_params.SqlCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=QueryResponse, - ) - - def list( - self, - *, - datasource_id: Optional[str] | NotGiven = NOT_GIVEN, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[QueryResponse, AsyncPage[QueryResponse]]: - """ - 获取所有的 Q2S 记录 - - Args: - datasource_id: 数据源 ID - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/single-turn/q2s", - page=AsyncPage[QueryResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "datasource_id": datasource_id, - "page": page, - "size": size, - }, - sql_list_params.SqlListParams, - ), - ), - model=QueryResponse, - ) - - -class SqlsResourceWithRawResponse: - def __init__(self, sqls: SqlsResource) -> None: - self._sqls = sqls - - self.create = to_raw_response_wrapper( - sqls.create, - ) - self.list = to_raw_response_wrapper( - sqls.list, - ) - - -class AsyncSqlsResourceWithRawResponse: - def __init__(self, sqls: AsyncSqlsResource) -> None: - self._sqls = sqls - - self.create = async_to_raw_response_wrapper( - sqls.create, - ) - self.list = async_to_raw_response_wrapper( - sqls.list, - ) - - -class SqlsResourceWithStreamingResponse: - def __init__(self, sqls: SqlsResource) -> None: - self._sqls = sqls - - self.create = to_streamed_response_wrapper( - sqls.create, - ) - self.list = to_streamed_response_wrapper( - sqls.list, - ) - - -class AsyncSqlsResourceWithStreamingResponse: - def __init__(self, sqls: AsyncSqlsResource) -> None: - self._sqls = sqls - - self.create = async_to_streamed_response_wrapper( - sqls.create, - ) - self.list = async_to_streamed_response_wrapper( - sqls.list, - ) diff --git a/src/asktable/resources/sys/projects/api_keys.py b/src/asktable/resources/sys/projects/api_keys.py index 4b17a377..aa3eb2b0 100644 --- a/src/asktable/resources/sys/projects/api_keys.py +++ b/src/asktable/resources/sys/projects/api_keys.py @@ -2,13 +2,13 @@ from __future__ import annotations -from typing import Optional +from typing import Dict, Optional from typing_extensions import Literal import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven -from ...._utils import maybe_transform, async_maybe_transform +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -21,11 +21,14 @@ from ....types.sys.projects import api_key_create_params, api_key_create_token_params from ....types.sys.projects.api_key_list_response import APIKeyListResponse from ....types.sys.projects.api_key_create_response import APIKeyCreateResponse +from ....types.sys.projects.api_key_create_token_response import APIKeyCreateTokenResponse __all__ = ["APIKeysResource", "AsyncAPIKeysResource"] class APIKeysResource(SyncAPIResource): + """系统管理""" + @cached_property def with_raw_response(self) -> APIKeysResourceWithRawResponse: """ @@ -49,13 +52,13 @@ def create( self, project_id: str, *, - ak_role: Literal["sys", "admin", "asker", "visitor"], + ak_role: Literal["sys", "admin", "asker"], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> APIKeyCreateResponse: """ 创建 API Key @@ -74,7 +77,7 @@ def create( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._post( - f"/v1/sys/projects/{project_id}/api-keys", + path_template("/v1/sys/projects/{project_id}/api-keys", project_id=project_id), body=maybe_transform({"ak_role": ak_role}, api_key_create_params.APIKeyCreateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -91,7 +94,7 @@ def list( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> APIKeyListResponse: """ List Api Keys @@ -108,7 +111,7 @@ def list( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get( - f"/v1/sys/projects/{project_id}/api-keys", + path_template("/v1/sys/projects/{project_id}/api-keys", project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -125,7 +128,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ Delete Api Key View @@ -145,7 +148,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/v1/sys/projects/{project_id}/api-keys/{key_id}", + path_template("/v1/sys/projects/{project_id}/api-keys/{key_id}", project_id=project_id, key_id=key_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -156,17 +159,17 @@ def create_token( self, project_id: str, *, - ak_role: Literal["sys", "admin", "asker", "visitor"] | NotGiven = NOT_GIVEN, - chat_role: Optional[api_key_create_token_params.ChatRole] | NotGiven = NOT_GIVEN, - token_ttl: int | NotGiven = NOT_GIVEN, - user_profile: Optional[object] | NotGiven = NOT_GIVEN, + ak_role: Literal["sys", "admin", "asker"] | Omit = omit, + chat_role: Optional[api_key_create_token_params.ChatRole] | Omit = omit, + token_ttl: int | Omit = omit, + user_profile: Optional[Dict[str, object]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APIKeyCreateTokenResponse: """ Create Token @@ -190,7 +193,7 @@ def create_token( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._post( - f"/v1/sys/projects/{project_id}/tokens", + path_template("/v1/sys/projects/{project_id}/tokens", project_id=project_id), body=maybe_transform( { "ak_role": ak_role, @@ -203,11 +206,13 @@ def create_token( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=APIKeyCreateTokenResponse, ) class AsyncAPIKeysResource(AsyncAPIResource): + """系统管理""" + @cached_property def with_raw_response(self) -> AsyncAPIKeysResourceWithRawResponse: """ @@ -231,13 +236,13 @@ async def create( self, project_id: str, *, - ak_role: Literal["sys", "admin", "asker", "visitor"], + ak_role: Literal["sys", "admin", "asker"], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> APIKeyCreateResponse: """ 创建 API Key @@ -256,7 +261,7 @@ async def create( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._post( - f"/v1/sys/projects/{project_id}/api-keys", + path_template("/v1/sys/projects/{project_id}/api-keys", project_id=project_id), body=await async_maybe_transform({"ak_role": ak_role}, api_key_create_params.APIKeyCreateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -273,7 +278,7 @@ async def list( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> APIKeyListResponse: """ List Api Keys @@ -290,7 +295,7 @@ async def list( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._get( - f"/v1/sys/projects/{project_id}/api-keys", + path_template("/v1/sys/projects/{project_id}/api-keys", project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -307,7 +312,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ Delete Api Key View @@ -327,7 +332,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `key_id` but received {key_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/v1/sys/projects/{project_id}/api-keys/{key_id}", + path_template("/v1/sys/projects/{project_id}/api-keys/{key_id}", project_id=project_id, key_id=key_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -338,17 +343,17 @@ async def create_token( self, project_id: str, *, - ak_role: Literal["sys", "admin", "asker", "visitor"] | NotGiven = NOT_GIVEN, - chat_role: Optional[api_key_create_token_params.ChatRole] | NotGiven = NOT_GIVEN, - token_ttl: int | NotGiven = NOT_GIVEN, - user_profile: Optional[object] | NotGiven = NOT_GIVEN, + ak_role: Literal["sys", "admin", "asker"] | Omit = omit, + chat_role: Optional[api_key_create_token_params.ChatRole] | Omit = omit, + token_ttl: int | Omit = omit, + user_profile: Optional[Dict[str, object]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> APIKeyCreateTokenResponse: """ Create Token @@ -372,7 +377,7 @@ async def create_token( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._post( - f"/v1/sys/projects/{project_id}/tokens", + path_template("/v1/sys/projects/{project_id}/tokens", project_id=project_id), body=await async_maybe_transform( { "ak_role": ak_role, @@ -385,7 +390,7 @@ async def create_token( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=APIKeyCreateTokenResponse, ) diff --git a/src/asktable/resources/sys/projects/projects.py b/src/asktable/resources/sys/projects/projects.py index 6c7c5f13..6719e39e 100644 --- a/src/asktable/resources/sys/projects/projects.py +++ b/src/asktable/resources/sys/projects/projects.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Optional +from typing import Dict, Optional import httpx @@ -14,8 +14,8 @@ APIKeysResourceWithStreamingResponse, AsyncAPIKeysResourceWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import maybe_transform, async_maybe_transform +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -28,14 +28,19 @@ from ....pagination import SyncPage, AsyncPage from ...._base_client import AsyncPaginator, make_request_options from ....types.sys.project import Project +from ....types.sys.project_export_response import ProjectExportResponse +from ....types.sys.project_import_response import ProjectImportResponse from ....types.sys.project_model_groups_response import ProjectModelGroupsResponse __all__ = ["ProjectsResource", "AsyncProjectsResource"] class ProjectsResource(SyncAPIResource): + """系统管理""" + @cached_property def api_keys(self) -> APIKeysResource: + """系统管理""" return APIKeysResource(self._client) @cached_property @@ -66,7 +71,7 @@ def create( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Create New Project @@ -100,7 +105,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Get Project @@ -117,7 +122,7 @@ def retrieve( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._get( - f"/v1/sys/projects/{project_id}", + path_template("/v1/sys/projects/{project_id}", project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -128,20 +133,23 @@ def update( self, project_id: str, *, - llm_model_group: Optional[str] | NotGiven = NOT_GIVEN, - locked: Optional[bool] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + is_public: Optional[bool] | Omit = omit, + llm_model_group: Optional[str] | Omit = omit, + locked: Optional[bool] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Update Project Args: + is_public: 是否公开项目 + llm_model_group: 模型组 locked: 是否锁定 @@ -159,9 +167,10 @@ def update( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._patch( - f"/v1/sys/projects/{project_id}", + path_template("/v1/sys/projects/{project_id}", project_id=project_id), body=maybe_transform( { + "is_public": is_public, "llm_model_group": llm_model_group, "locked": locked, "name": name, @@ -177,15 +186,15 @@ def update( def list( self, *, - page: int | NotGiven = NOT_GIVEN, - project_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, + page: int | Omit = omit, + project_ids: Optional[SequenceNotStr[str]] | Omit = omit, + size: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncPage[Project]: """ Get Projects @@ -234,7 +243,7 @@ def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ Delete Project @@ -251,7 +260,7 @@ def delete( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._delete( - f"/v1/sys/projects/{project_id}", + path_template("/v1/sys/projects/{project_id}", project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -267,8 +276,8 @@ def export( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectExportResponse: """ Export Project @@ -284,24 +293,24 @@ def export( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return self._post( - f"/v1/sys/projects/{project_id}/export", + path_template("/v1/sys/projects/{project_id}/export", project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=ProjectExportResponse, ) def import_( self, *, - body: object, + body: Dict[str, object], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectImportResponse: """ Import Project @@ -320,7 +329,7 @@ def import_( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=ProjectImportResponse, ) def model_groups( @@ -331,9 +340,9 @@ def model_groups( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProjectModelGroupsResponse: - """Get Llm Model Groups""" + """Get Model Groups""" return self._get( "/v1/sys/projects/model-groups", options=make_request_options( @@ -344,8 +353,11 @@ def model_groups( class AsyncProjectsResource(AsyncAPIResource): + """系统管理""" + @cached_property def api_keys(self) -> AsyncAPIKeysResource: + """系统管理""" return AsyncAPIKeysResource(self._client) @cached_property @@ -376,7 +388,7 @@ async def create( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Create New Project @@ -410,7 +422,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Get Project @@ -427,7 +439,7 @@ async def retrieve( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._get( - f"/v1/sys/projects/{project_id}", + path_template("/v1/sys/projects/{project_id}", project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -438,20 +450,23 @@ async def update( self, project_id: str, *, - llm_model_group: Optional[str] | NotGiven = NOT_GIVEN, - locked: Optional[bool] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + is_public: Optional[bool] | Omit = omit, + llm_model_group: Optional[str] | Omit = omit, + locked: Optional[bool] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Update Project Args: + is_public: 是否公开项目 + llm_model_group: 模型组 locked: 是否锁定 @@ -469,9 +484,10 @@ async def update( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._patch( - f"/v1/sys/projects/{project_id}", + path_template("/v1/sys/projects/{project_id}", project_id=project_id), body=await async_maybe_transform( { + "is_public": is_public, "llm_model_group": llm_model_group, "locked": locked, "name": name, @@ -487,15 +503,15 @@ async def update( def list( self, *, - page: int | NotGiven = NOT_GIVEN, - project_ids: Optional[List[str]] | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, + page: int | Omit = omit, + project_ids: Optional[SequenceNotStr[str]] | Omit = omit, + size: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Project, AsyncPage[Project]]: """ Get Projects @@ -544,7 +560,7 @@ async def delete( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> object: """ Delete Project @@ -561,7 +577,7 @@ async def delete( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._delete( - f"/v1/sys/projects/{project_id}", + path_template("/v1/sys/projects/{project_id}", project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -577,8 +593,8 @@ async def export( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectExportResponse: """ Export Project @@ -594,24 +610,24 @@ async def export( if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") return await self._post( - f"/v1/sys/projects/{project_id}/export", + path_template("/v1/sys/projects/{project_id}/export", project_id=project_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=ProjectExportResponse, ) async def import_( self, *, - body: object, + body: Dict[str, object], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectImportResponse: """ Import Project @@ -630,7 +646,7 @@ async def import_( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=object, + cast_to=ProjectImportResponse, ) async def model_groups( @@ -641,9 +657,9 @@ async def model_groups( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProjectModelGroupsResponse: - """Get Llm Model Groups""" + """Get Model Groups""" return await self._get( "/v1/sys/projects/model-groups", options=make_request_options( @@ -684,6 +700,7 @@ def __init__(self, projects: ProjectsResource) -> None: @cached_property def api_keys(self) -> APIKeysResourceWithRawResponse: + """系统管理""" return APIKeysResourceWithRawResponse(self._projects.api_keys) @@ -718,6 +735,7 @@ def __init__(self, projects: AsyncProjectsResource) -> None: @cached_property def api_keys(self) -> AsyncAPIKeysResourceWithRawResponse: + """系统管理""" return AsyncAPIKeysResourceWithRawResponse(self._projects.api_keys) @@ -752,6 +770,7 @@ def __init__(self, projects: ProjectsResource) -> None: @cached_property def api_keys(self) -> APIKeysResourceWithStreamingResponse: + """系统管理""" return APIKeysResourceWithStreamingResponse(self._projects.api_keys) @@ -786,4 +805,5 @@ def __init__(self, projects: AsyncProjectsResource) -> None: @cached_property def api_keys(self) -> AsyncAPIKeysResourceWithStreamingResponse: + """系统管理""" return AsyncAPIKeysResourceWithStreamingResponse(self._projects.api_keys) diff --git a/src/asktable/resources/sys/sys.py b/src/asktable/resources/sys/sys.py index 3ab1213c..9352d837 100644 --- a/src/asktable/resources/sys/sys.py +++ b/src/asktable/resources/sys/sys.py @@ -2,22 +2,8 @@ from __future__ import annotations -from typing import Optional - -import httpx - -from ...types import sy_update_config_params -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..._base_client import make_request_options from .projects.projects import ( ProjectsResource, AsyncProjectsResource, @@ -26,7 +12,6 @@ ProjectsResourceWithStreamingResponse, AsyncProjectsResourceWithStreamingResponse, ) -from ...types.sy_update_config_response import SyUpdateConfigResponse __all__ = ["SysResource", "AsyncSysResource"] @@ -34,6 +19,7 @@ class SysResource(SyncAPIResource): @cached_property def projects(self) -> ProjectsResource: + """系统管理""" return ProjectsResource(self._client) @cached_property @@ -55,46 +41,11 @@ def with_streaming_response(self) -> SysResourceWithStreamingResponse: """ return SysResourceWithStreamingResponse(self) - def update_config( - self, - *, - global_table_limit: Optional[int] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyUpdateConfigResponse: - """ - Update Config - - Args: - global_table_limit: 表限制数量 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._patch( - "/v1/sys/config", - body=maybe_transform( - {"global_table_limit": global_table_limit}, sy_update_config_params.SyUpdateConfigParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SyUpdateConfigResponse, - ) - class AsyncSysResource(AsyncAPIResource): @cached_property def projects(self) -> AsyncProjectsResource: + """系统管理""" return AsyncProjectsResource(self._client) @cached_property @@ -116,53 +67,14 @@ def with_streaming_response(self) -> AsyncSysResourceWithStreamingResponse: """ return AsyncSysResourceWithStreamingResponse(self) - async def update_config( - self, - *, - global_table_limit: Optional[int] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyUpdateConfigResponse: - """ - Update Config - - Args: - global_table_limit: 表限制数量 - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._patch( - "/v1/sys/config", - body=await async_maybe_transform( - {"global_table_limit": global_table_limit}, sy_update_config_params.SyUpdateConfigParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SyUpdateConfigResponse, - ) - class SysResourceWithRawResponse: def __init__(self, sys: SysResource) -> None: self._sys = sys - self.update_config = to_raw_response_wrapper( - sys.update_config, - ) - @cached_property def projects(self) -> ProjectsResourceWithRawResponse: + """系统管理""" return ProjectsResourceWithRawResponse(self._sys.projects) @@ -170,12 +82,9 @@ class AsyncSysResourceWithRawResponse: def __init__(self, sys: AsyncSysResource) -> None: self._sys = sys - self.update_config = async_to_raw_response_wrapper( - sys.update_config, - ) - @cached_property def projects(self) -> AsyncProjectsResourceWithRawResponse: + """系统管理""" return AsyncProjectsResourceWithRawResponse(self._sys.projects) @@ -183,12 +92,9 @@ class SysResourceWithStreamingResponse: def __init__(self, sys: SysResource) -> None: self._sys = sys - self.update_config = to_streamed_response_wrapper( - sys.update_config, - ) - @cached_property def projects(self) -> ProjectsResourceWithStreamingResponse: + """系统管理""" return ProjectsResourceWithStreamingResponse(self._sys.projects) @@ -196,10 +102,7 @@ class AsyncSysResourceWithStreamingResponse: def __init__(self, sys: AsyncSysResource) -> None: self._sys = sys - self.update_config = async_to_streamed_response_wrapper( - sys.update_config, - ) - @cached_property def projects(self) -> AsyncProjectsResourceWithStreamingResponse: + """系统管理""" return AsyncProjectsResourceWithStreamingResponse(self._sys.projects) diff --git a/src/asktable/resources/trainings.py b/src/asktable/resources/trainings.py deleted file mode 100644 index 98882a5c..00000000 --- a/src/asktable/resources/trainings.py +++ /dev/null @@ -1,528 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable, Optional - -import httpx - -from ..types import training_list_params, training_create_params, training_delete_params, training_update_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..pagination import SyncPage, AsyncPage -from .._base_client import AsyncPaginator, make_request_options -from ..types.training_list_response import TrainingListResponse -from ..types.training_create_response import TrainingCreateResponse -from ..types.training_update_response import TrainingUpdateResponse - -__all__ = ["TrainingsResource", "AsyncTrainingsResource"] - - -class TrainingsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> TrainingsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return TrainingsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TrainingsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return TrainingsResourceWithStreamingResponse(self) - - def create( - self, - *, - datasource_id: str, - body: Iterable[training_create_params.Body], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TrainingCreateResponse: - """ - Create Training Pair - - Args: - datasource_id: 数据源 ID - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/training", - body=maybe_transform(body, Iterable[training_create_params.Body]), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"datasource_id": datasource_id}, training_create_params.TrainingCreateParams), - ), - cast_to=TrainingCreateResponse, - ) - - def update( - self, - id: str, - *, - datasource_id: str, - active: Optional[bool] | NotGiven = NOT_GIVEN, - question: Optional[str] | NotGiven = NOT_GIVEN, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - sql: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TrainingUpdateResponse: - """ - Update Training Pair - - Args: - datasource_id: 数据源 ID - - active: 是否启用 - - question: 用户问题 - - role_id: 角色 ID - - sql: 用户问题对应的 SQL - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._patch( - f"/v1/training/{id}", - body=maybe_transform( - { - "active": active, - "question": question, - "role_id": role_id, - "sql": sql, - }, - training_update_params.TrainingUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"datasource_id": datasource_id}, training_update_params.TrainingUpdateParams), - ), - cast_to=TrainingUpdateResponse, - ) - - def list( - self, - *, - datasource_id: str, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[TrainingListResponse]: - """ - Get Training Pairs - - Args: - datasource_id: 数据源 ID - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/training", - page=SyncPage[TrainingListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "datasource_id": datasource_id, - "page": page, - "size": size, - }, - training_list_params.TrainingListParams, - ), - ), - model=TrainingListResponse, - ) - - def delete( - self, - id: str, - *, - datasource_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - Delete Training Pair - - Args: - datasource_id: 数据源 ID - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._delete( - f"/v1/training/{id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"datasource_id": datasource_id}, training_delete_params.TrainingDeleteParams), - ), - cast_to=object, - ) - - -class AsyncTrainingsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncTrainingsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/DataMini/asktable-python#accessing-raw-response-data-eg-headers - """ - return AsyncTrainingsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTrainingsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/DataMini/asktable-python#with_streaming_response - """ - return AsyncTrainingsResourceWithStreamingResponse(self) - - async def create( - self, - *, - datasource_id: str, - body: Iterable[training_create_params.Body], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TrainingCreateResponse: - """ - Create Training Pair - - Args: - datasource_id: 数据源 ID - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/training", - body=await async_maybe_transform(body, Iterable[training_create_params.Body]), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"datasource_id": datasource_id}, training_create_params.TrainingCreateParams - ), - ), - cast_to=TrainingCreateResponse, - ) - - async def update( - self, - id: str, - *, - datasource_id: str, - active: Optional[bool] | NotGiven = NOT_GIVEN, - question: Optional[str] | NotGiven = NOT_GIVEN, - role_id: Optional[str] | NotGiven = NOT_GIVEN, - sql: Optional[str] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> TrainingUpdateResponse: - """ - Update Training Pair - - Args: - datasource_id: 数据源 ID - - active: 是否启用 - - question: 用户问题 - - role_id: 角色 ID - - sql: 用户问题对应的 SQL - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._patch( - f"/v1/training/{id}", - body=await async_maybe_transform( - { - "active": active, - "question": question, - "role_id": role_id, - "sql": sql, - }, - training_update_params.TrainingUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"datasource_id": datasource_id}, training_update_params.TrainingUpdateParams - ), - ), - cast_to=TrainingUpdateResponse, - ) - - def list( - self, - *, - datasource_id: str, - page: int | NotGiven = NOT_GIVEN, - size: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[TrainingListResponse, AsyncPage[TrainingListResponse]]: - """ - Get Training Pairs - - Args: - datasource_id: 数据源 ID - - page: Page number - - size: Page size - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/training", - page=AsyncPage[TrainingListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "datasource_id": datasource_id, - "page": page, - "size": size, - }, - training_list_params.TrainingListParams, - ), - ), - model=TrainingListResponse, - ) - - async def delete( - self, - id: str, - *, - datasource_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> object: - """ - Delete Training Pair - - Args: - datasource_id: 数据源 ID - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._delete( - f"/v1/training/{id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"datasource_id": datasource_id}, training_delete_params.TrainingDeleteParams - ), - ), - cast_to=object, - ) - - -class TrainingsResourceWithRawResponse: - def __init__(self, trainings: TrainingsResource) -> None: - self._trainings = trainings - - self.create = to_raw_response_wrapper( - trainings.create, - ) - self.update = to_raw_response_wrapper( - trainings.update, - ) - self.list = to_raw_response_wrapper( - trainings.list, - ) - self.delete = to_raw_response_wrapper( - trainings.delete, - ) - - -class AsyncTrainingsResourceWithRawResponse: - def __init__(self, trainings: AsyncTrainingsResource) -> None: - self._trainings = trainings - - self.create = async_to_raw_response_wrapper( - trainings.create, - ) - self.update = async_to_raw_response_wrapper( - trainings.update, - ) - self.list = async_to_raw_response_wrapper( - trainings.list, - ) - self.delete = async_to_raw_response_wrapper( - trainings.delete, - ) - - -class TrainingsResourceWithStreamingResponse: - def __init__(self, trainings: TrainingsResource) -> None: - self._trainings = trainings - - self.create = to_streamed_response_wrapper( - trainings.create, - ) - self.update = to_streamed_response_wrapper( - trainings.update, - ) - self.list = to_streamed_response_wrapper( - trainings.list, - ) - self.delete = to_streamed_response_wrapper( - trainings.delete, - ) - - -class AsyncTrainingsResourceWithStreamingResponse: - def __init__(self, trainings: AsyncTrainingsResource) -> None: - self._trainings = trainings - - self.create = async_to_streamed_response_wrapper( - trainings.create, - ) - self.update = async_to_streamed_response_wrapper( - trainings.update, - ) - self.list = async_to_streamed_response_wrapper( - trainings.list, - ) - self.delete = async_to_streamed_response_wrapper( - trainings.delete, - ) diff --git a/src/asktable/resources/user/projects.py b/src/asktable/resources/user/projects.py index 27ba7426..324dd9ac 100644 --- a/src/asktable/resources/user/projects.py +++ b/src/asktable/resources/user/projects.py @@ -6,7 +6,7 @@ import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -25,6 +25,8 @@ class ProjectsResource(SyncAPIResource): + """我的项目""" + @cached_property def with_raw_response(self) -> ProjectsResourceWithRawResponse: """ @@ -52,7 +54,7 @@ def retrieve_model_groups( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProjectRetrieveModelGroupsResponse: """Get Llm Model Groups""" return self._get( @@ -71,7 +73,7 @@ def retrieve_my_project( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """Get My Project""" return self._get( @@ -85,14 +87,14 @@ def retrieve_my_project( def update_my_project( self, *, - llm_model_group: Optional[str] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + llm_model_group: Optional[str] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Update My Project @@ -127,6 +129,8 @@ def update_my_project( class AsyncProjectsResource(AsyncAPIResource): + """我的项目""" + @cached_property def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse: """ @@ -154,7 +158,7 @@ async def retrieve_model_groups( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ProjectRetrieveModelGroupsResponse: """Get Llm Model Groups""" return await self._get( @@ -173,7 +177,7 @@ async def retrieve_my_project( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """Get My Project""" return await self._get( @@ -187,14 +191,14 @@ async def retrieve_my_project( async def update_my_project( self, *, - llm_model_group: Optional[str] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + llm_model_group: Optional[str] | Omit = omit, + name: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Project: """ Update My Project diff --git a/src/asktable/resources/user/user.py b/src/asktable/resources/user/user.py index 981d0969..970be13c 100644 --- a/src/asktable/resources/user/user.py +++ b/src/asktable/resources/user/user.py @@ -19,6 +19,7 @@ class UserResource(SyncAPIResource): @cached_property def projects(self) -> ProjectsResource: + """我的项目""" return ProjectsResource(self._client) @cached_property @@ -44,6 +45,7 @@ def with_streaming_response(self) -> UserResourceWithStreamingResponse: class AsyncUserResource(AsyncAPIResource): @cached_property def projects(self) -> AsyncProjectsResource: + """我的项目""" return AsyncProjectsResource(self._client) @cached_property @@ -72,6 +74,7 @@ def __init__(self, user: UserResource) -> None: @cached_property def projects(self) -> ProjectsResourceWithRawResponse: + """我的项目""" return ProjectsResourceWithRawResponse(self._user.projects) @@ -81,6 +84,7 @@ def __init__(self, user: AsyncUserResource) -> None: @cached_property def projects(self) -> AsyncProjectsResourceWithRawResponse: + """我的项目""" return AsyncProjectsResourceWithRawResponse(self._user.projects) @@ -90,6 +94,7 @@ def __init__(self, user: UserResource) -> None: @cached_property def projects(self) -> ProjectsResourceWithStreamingResponse: + """我的项目""" return ProjectsResourceWithStreamingResponse(self._user.projects) @@ -99,4 +104,5 @@ def __init__(self, user: AsyncUserResource) -> None: @cached_property def projects(self) -> AsyncProjectsResourceWithStreamingResponse: + """我的项目""" return AsyncProjectsResourceWithStreamingResponse(self._user.projects) diff --git a/src/asktable/types/__init__.py b/src/asktable/types/__init__.py index 640c9f4b..ea089aa5 100644 --- a/src/asktable/types/__init__.py +++ b/src/asktable/types/__init__.py @@ -2,88 +2,25 @@ from __future__ import annotations -from .chat import Chat as Chat from .meta import Meta as Meta -from .role import Role as Role -from .entry import Entry as Entry from .index import Index as Index from .shared import Policy as Policy -from .chatbot import Chatbot as Chatbot -from .ai_message import AIMessage as AIMessage from .datasource import Datasource as Datasource -from .tool_message import ToolMessage as ToolMessage -from .user_message import UserMessage as UserMessage -from .secure_tunnel import SecureTunnel as SecureTunnel -from .query_response import QueryResponse as QueryResponse -from .answer_response import AnswerResponse as AnswerResponse -from .ats_list_params import ATSListParams as ATSListParams -from .bot_list_params import BotListParams as BotListParams -from .sql_list_params import SqlListParams as SqlListParams from .auth_me_response import AuthMeResponse as AuthMeResponse -from .chat_list_params import ChatListParams as ChatListParams -from .role_list_params import RoleListParams as RoleListParams -from .ats_create_params import ATSCreateParams as ATSCreateParams -from .ats_delete_params import ATSDeleteParams as ATSDeleteParams -from .ats_list_response import ATSListResponse as ATSListResponse -from .ats_update_params import ATSUpdateParams as ATSUpdateParams -from .bot_create_params import BotCreateParams as BotCreateParams -from .bot_invite_params import BotInviteParams as BotInviteParams -from .bot_update_params import BotUpdateParams as BotUpdateParams -from .file_ask_response import FileAskResponse as FileAskResponse -from .sql_create_params import SqlCreateParams as SqlCreateParams -from .answer_list_params import AnswerListParams as AnswerListParams -from .chat_create_params import ChatCreateParams as ChatCreateParams -from .policy_list_params import PolicyListParams as PolicyListParams -from .role_create_params import RoleCreateParams as RoleCreateParams -from .role_update_params import RoleUpdateParams as RoleUpdateParams -from .ats_create_response import ATSCreateResponse as ATSCreateResponse -from .ats_update_response import ATSUpdateResponse as ATSUpdateResponse from .score_create_params import ScoreCreateParams as ScoreCreateParams -from .answer_create_params import AnswerCreateParams as AnswerCreateParams -from .policy_create_params import PolicyCreateParams as PolicyCreateParams -from .policy_update_params import PolicyUpdateParams as PolicyUpdateParams from .polish_create_params import PolishCreateParams as PolishCreateParams -from .training_list_params import TrainingListParams as TrainingListParams -from .ats_retrieve_response import ATSRetrieveResponse as ATSRetrieveResponse -from .entry_with_definition import EntryWithDefinition as EntryWithDefinition from .project_update_params import ProjectUpdateParams as ProjectUpdateParams -from .score_create_response import ScoreCreateResponse as ScoreCreateResponse -from .chat_retrieve_response import ChatRetrieveResponse as ChatRetrieveResponse from .datasource_list_params import DatasourceListParams as DatasourceListParams from .polish_create_response import PolishCreateResponse as PolishCreateResponse -from .training_create_params import TrainingCreateParams as TrainingCreateParams -from .training_delete_params import TrainingDeleteParams as TrainingDeleteParams -from .training_list_response import TrainingListResponse as TrainingListResponse -from .training_update_params import TrainingUpdateParams as TrainingUpdateParams -from .sy_update_config_params import SyUpdateConfigParams as SyUpdateConfigParams from .auth_create_token_params import AuthCreateTokenParams as AuthCreateTokenParams from .datasource_create_params import DatasourceCreateParams as DatasourceCreateParams from .datasource_update_params import DatasourceUpdateParams as DatasourceUpdateParams -from .preference_create_params import PreferenceCreateParams as PreferenceCreateParams -from .preference_update_params import PreferenceUpdateParams as PreferenceUpdateParams -from .securetunnel_list_params import SecuretunnelListParams as SecuretunnelListParams -from .training_create_response import TrainingCreateResponse as TrainingCreateResponse -from .training_update_response import TrainingUpdateResponse as TrainingUpdateResponse -from .role_get_polices_response import RoleGetPolicesResponse as RoleGetPolicesResponse -from .role_get_variables_params import RoleGetVariablesParams as RoleGetVariablesParams -from .sy_update_config_response import SyUpdateConfigResponse as SyUpdateConfigResponse +from .auth_create_token_response import AuthCreateTokenResponse as AuthCreateTokenResponse from .datasource_add_file_params import DatasourceAddFileParams as DatasourceAddFileParams -from .preference_create_response import PreferenceCreateResponse as PreferenceCreateResponse -from .preference_update_response import PreferenceUpdateResponse as PreferenceUpdateResponse -from .securetunnel_create_params import SecuretunnelCreateParams as SecuretunnelCreateParams -from .securetunnel_update_params import SecuretunnelUpdateParams as SecuretunnelUpdateParams from .dataframe_retrieve_response import DataframeRetrieveResponse as DataframeRetrieveResponse from .datasource_retrieve_response import DatasourceRetrieveResponse as DatasourceRetrieveResponse -from .preference_retrieve_response import PreferenceRetrieveResponse as PreferenceRetrieveResponse -from .business_glossary_list_params import BusinessGlossaryListParams as BusinessGlossaryListParams from .datasource_update_field_params import DatasourceUpdateFieldParams as DatasourceUpdateFieldParams -from .securetunnel_list_links_params import SecuretunnelListLinksParams as SecuretunnelListLinksParams -from .business_glossary_create_params import BusinessGlossaryCreateParams as BusinessGlossaryCreateParams -from .business_glossary_update_params import BusinessGlossaryUpdateParams as BusinessGlossaryUpdateParams from .integration_excel_csv_ask_params import IntegrationExcelCsvAskParams as IntegrationExcelCsvAskParams -from .securetunnel_list_links_response import SecuretunnelListLinksResponse as SecuretunnelListLinksResponse -from .business_glossary_create_response import BusinessGlossaryCreateResponse as BusinessGlossaryCreateResponse -from .integration_create_excel_ds_params import IntegrationCreateExcelDsParams as IntegrationCreateExcelDsParams from .project_list_model_groups_response import ProjectListModelGroupsResponse as ProjectListModelGroupsResponse from .datasource_retrieve_runtime_meta_response import ( DatasourceRetrieveRuntimeMetaResponse as DatasourceRetrieveRuntimeMetaResponse, diff --git a/src/asktable/types/ai_message.py b/src/asktable/types/ai_message.py deleted file mode 100644 index 986e1827..00000000 --- a/src/asktable/types/ai_message.py +++ /dev/null @@ -1,63 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["AIMessage", "Content", "ContentAttachment", "ToolCall", "ToolCallFunction"] - - -class ContentAttachment(BaseModel): - info: object - - type: str - """The type of the attachment""" - - -class Content(BaseModel): - text: str - - attachments: Optional[List[ContentAttachment]] = None - - -class ToolCallFunction(BaseModel): - arguments: str - - name: str - - -class ToolCall(BaseModel): - id: str - - function: ToolCallFunction - - type: Optional[Literal["function"]] = None - - -class AIMessage(BaseModel): - content: Content - - id: Optional[str] = None - - created_at: Optional[datetime] = None - """创建时间""" - - dataframe_ids: Optional[List[str]] = None - - end_turn: Optional[bool] = None - - metadata: Optional[object] = None - - name: Optional[str] = None - - reply_to_msg_id: Optional[str] = None - - role: Optional[Literal["ai"]] = None - - status: Optional[str] = None - - tool_calls: Optional[List[ToolCall]] = None - - trace_id: Optional[str] = None diff --git a/src/asktable/types/answer_create_params.py b/src/asktable/types/answer_create_params.py deleted file mode 100644 index b4fcd62f..00000000 --- a/src/asktable/types/answer_create_params.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -__all__ = ["AnswerCreateParams"] - - -class AnswerCreateParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" - - question: Required[str] - """查询语句""" - - max_rows: Optional[int] - """最大返回行数,默认为 0,即不限制返回行数""" - - role_id: Optional[str] - """ - 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - """ - - role_variables: Optional[object] - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" - - with_json: Optional[bool] - """是否同时将数据,作为 json 格式的附件一起返回""" diff --git a/src/asktable/types/answer_list_params.py b/src/asktable/types/answer_list_params.py deleted file mode 100644 index 471c206f..00000000 --- a/src/asktable/types/answer_list_params.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -__all__ = ["AnswerListParams"] - - -class AnswerListParams(TypedDict, total=False): - datasource_id: Optional[str] - """数据源 ID""" - - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/answer_response.py b/src/asktable/types/answer_response.py deleted file mode 100644 index 04112480..00000000 --- a/src/asktable/types/answer_response.py +++ /dev/null @@ -1,76 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["AnswerResponse", "Answer", "AnswerAttachment", "Request", "Timing"] - - -class AnswerAttachment(BaseModel): - info: object - - type: str - """The type of the attachment""" - - -class Answer(BaseModel): - text: str - - attachments: Optional[List[AnswerAttachment]] = None - - -class Request(BaseModel): - datasource_id: str - """数据源 ID""" - - question: str - """查询语句""" - - max_rows: Optional[int] = None - """最大返回行数,默认为 0,即不限制返回行数""" - - role_id: Optional[str] = None - """ - 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - """ - - role_variables: Optional[object] = None - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" - - with_json: Optional[bool] = None - """是否同时将数据,作为 json 格式的附件一起返回""" - - -class Timing(BaseModel): - accessor_duration: Optional[float] = None - - llm_duration: Optional[float] = None - - total_duration: Optional[float] = None - - -class AnswerResponse(BaseModel): - id: str - - answer: Optional[Answer] = None - - created_at: datetime - - duration: int - - modified_at: datetime - - project_id: str - - request: Request - - status: str - - err_msg: Optional[str] = None - - timing: Optional[Timing] = None - - trace_id: Optional[str] = None diff --git a/src/asktable/types/ats/__init__.py b/src/asktable/types/ats/__init__.py index bcd2ea3d..f8ee8b14 100644 --- a/src/asktable/types/ats/__init__.py +++ b/src/asktable/types/ats/__init__.py @@ -1,18 +1,3 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from __future__ import annotations - -from .task_run_params import TaskRunParams as TaskRunParams -from .task_list_params import TaskListParams as TaskListParams -from .task_run_response import TaskRunResponse as TaskRunResponse -from .task_list_response import TaskListResponse as TaskListResponse -from .test_case_list_params import TestCaseListParams as TestCaseListParams -from .task_retrieve_response import TaskRetrieveResponse as TaskRetrieveResponse -from .test_case_create_params import TestCaseCreateParams as TestCaseCreateParams -from .test_case_list_response import TestCaseListResponse as TestCaseListResponse -from .test_case_update_params import TestCaseUpdateParams as TestCaseUpdateParams -from .test_case_create_response import TestCaseCreateResponse as TestCaseCreateResponse -from .test_case_update_response import TestCaseUpdateResponse as TestCaseUpdateResponse -from .task_get_case_tasks_params import TaskGetCaseTasksParams as TaskGetCaseTasksParams -from .test_case_retrieve_response import TestCaseRetrieveResponse as TestCaseRetrieveResponse -from .task_get_case_tasks_response import TaskGetCaseTasksResponse as TaskGetCaseTasksResponse diff --git a/src/asktable/types/ats/task_get_case_tasks_params.py b/src/asktable/types/ats/task_get_case_tasks_params.py deleted file mode 100644 index 6b90d2a7..00000000 --- a/src/asktable/types/ats/task_get_case_tasks_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["TaskGetCaseTasksParams"] - - -class TaskGetCaseTasksParams(TypedDict, total=False): - ats_id: Required[str] - - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/ats/task_get_case_tasks_response.py b/src/asktable/types/ats/task_get_case_tasks_response.py deleted file mode 100644 index 0592193e..00000000 --- a/src/asktable/types/ats/task_get_case_tasks_response.py +++ /dev/null @@ -1,73 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["TaskGetCaseTasksResponse", "Item"] - - -class Item(BaseModel): - id: str - """测试用例运行记录 ID""" - - ats_task_id: str - """对应的测试任务 ID""" - - created_at: datetime - """创建时间""" - - expected_sql: str - """sql 答案""" - - modified_at: datetime - """修改时间""" - - question: str - """提问内容""" - - status: str - """测试状态""" - - atc_id: Optional[str] = None - """对应的测试用例 ID""" - - duration: Optional[float] = None - """测试用例执行时间,单位为秒""" - - expected_query_result: Union[List[object], object, None] = None - """预期查询出来的数据""" - - generated_sql: Optional[str] = None - """生成的 sql""" - - generated_sql_query_result: Union[List[object], object, None] = None - """测试样本生成的 sql 查询结果""" - - last_run: Optional[datetime] = None - """上次该测试样例运行时间""" - - role_id: Optional[str] = None - """角色 ID""" - - role_variables: Optional[object] = None - """扮演角色需要传递的值""" - - status_message: Optional[str] = None - """测试日志保存字段""" - - task_id: Optional[str] = None - """测试调用接口对应任务的 id""" - - -class TaskGetCaseTasksResponse(BaseModel): - items: List[Item] - - page: Optional[int] = None - - size: Optional[int] = None - - total: Optional[int] = None - - pages: Optional[int] = None diff --git a/src/asktable/types/ats/task_list_params.py b/src/asktable/types/ats/task_list_params.py deleted file mode 100644 index 8a9f52c2..00000000 --- a/src/asktable/types/ats/task_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["TaskListParams"] - - -class TaskListParams(TypedDict, total=False): - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/ats/task_list_response.py b/src/asktable/types/ats/task_list_response.py deleted file mode 100644 index a3591ca0..00000000 --- a/src/asktable/types/ats/task_list_response.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["TaskListResponse"] - - -class TaskListResponse(BaseModel): - id: str - """测试任务 ID""" - - accuracy: float - """测试正确率""" - - ats_id: str - """测试集 ID""" - - completed_case_count: int - """已完成测试用例数""" - - created_at: datetime - """创建时间""" - - failed_case_count: int - """未通过测试用例数""" - - modified_at: datetime - """修改时间""" - - passed_case_count: int - """通过测试用例数""" - - status: str - """测试状态""" - - total_case_count: int - """测试用例总数""" - - duration: Optional[float] = None - """测试任务时间,单位为秒""" - - last_run: Optional[datetime] = None - """上次测试运行时间""" - - status_message: Optional[str] = None - """测试日志""" diff --git a/src/asktable/types/ats/task_retrieve_response.py b/src/asktable/types/ats/task_retrieve_response.py deleted file mode 100644 index bc81d5bc..00000000 --- a/src/asktable/types/ats/task_retrieve_response.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["TaskRetrieveResponse"] - - -class TaskRetrieveResponse(BaseModel): - id: str - """测试任务 ID""" - - accuracy: float - """测试正确率""" - - ats_id: str - """测试集 ID""" - - completed_case_count: int - """已完成测试用例数""" - - created_at: datetime - """创建时间""" - - failed_case_count: int - """未通过测试用例数""" - - modified_at: datetime - """修改时间""" - - passed_case_count: int - """通过测试用例数""" - - status: str - """测试状态""" - - total_case_count: int - """测试用例总数""" - - duration: Optional[float] = None - """测试任务时间,单位为秒""" - - last_run: Optional[datetime] = None - """上次测试运行时间""" - - status_message: Optional[str] = None - """测试日志""" diff --git a/src/asktable/types/ats/task_run_params.py b/src/asktable/types/ats/task_run_params.py deleted file mode 100644 index b86b4193..00000000 --- a/src/asktable/types/ats/task_run_params.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Required, TypedDict - -__all__ = ["TaskRunParams"] - - -class TaskRunParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" - - specific_case_ids: Required[List[str]] - """测试用例 ID 列表""" diff --git a/src/asktable/types/ats/task_run_response.py b/src/asktable/types/ats/task_run_response.py deleted file mode 100644 index fbc3533c..00000000 --- a/src/asktable/types/ats/task_run_response.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["TaskRunResponse"] - - -class TaskRunResponse(BaseModel): - id: str - """测试任务 ID""" - - accuracy: float - """测试正确率""" - - ats_id: str - """测试集 ID""" - - completed_case_count: int - """已完成测试用例数""" - - created_at: datetime - """创建时间""" - - failed_case_count: int - """未通过测试用例数""" - - modified_at: datetime - """修改时间""" - - passed_case_count: int - """通过测试用例数""" - - status: str - """测试状态""" - - total_case_count: int - """测试用例总数""" - - duration: Optional[float] = None - """测试任务时间,单位为秒""" - - last_run: Optional[datetime] = None - """上次测试运行时间""" - - status_message: Optional[str] = None - """测试日志""" diff --git a/src/asktable/types/ats/test_case_create_params.py b/src/asktable/types/ats/test_case_create_params.py deleted file mode 100644 index 229132b2..00000000 --- a/src/asktable/types/ats/test_case_create_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -__all__ = ["TestCaseCreateParams"] - - -class TestCaseCreateParams(TypedDict, total=False): - expected_sql: Required[str] - """用户期望生成的 sql""" - - question: Required[str] - """用户提问""" - - role_id: Optional[str] - """角色 ID""" - - role_variables: Optional[object] - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" diff --git a/src/asktable/types/ats/test_case_create_response.py b/src/asktable/types/ats/test_case_create_response.py deleted file mode 100644 index 0faa6a83..00000000 --- a/src/asktable/types/ats/test_case_create_response.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["TestCaseCreateResponse"] - - -class TestCaseCreateResponse(BaseModel): - __test__ = False - id: str - """测试样例 ID""" - - ats_id: str - """所属的测试集 ID""" - - created_at: datetime - """创建时间""" - - expected_sql: str - """用户期望生成的 sql""" - - modified_at: datetime - """修改时间""" - - question: str - """用户提问""" - - role_id: Optional[str] = None - """角色 ID""" - - role_variables: Optional[object] = None - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" diff --git a/src/asktable/types/ats/test_case_list_params.py b/src/asktable/types/ats/test_case_list_params.py deleted file mode 100644 index 603b4898..00000000 --- a/src/asktable/types/ats/test_case_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["TestCaseListParams"] - - -class TestCaseListParams(TypedDict, total=False): - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/ats/test_case_list_response.py b/src/asktable/types/ats/test_case_list_response.py deleted file mode 100644 index 4216c794..00000000 --- a/src/asktable/types/ats/test_case_list_response.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["TestCaseListResponse"] - - -class TestCaseListResponse(BaseModel): - __test__ = False - id: str - """测试样例 ID""" - - ats_id: str - """所属的测试集 ID""" - - created_at: datetime - """创建时间""" - - expected_sql: str - """用户期望生成的 sql""" - - modified_at: datetime - """修改时间""" - - question: str - """用户提问""" - - role_id: Optional[str] = None - """角色 ID""" - - role_variables: Optional[object] = None - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" diff --git a/src/asktable/types/ats/test_case_retrieve_response.py b/src/asktable/types/ats/test_case_retrieve_response.py deleted file mode 100644 index 951aee1d..00000000 --- a/src/asktable/types/ats/test_case_retrieve_response.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["TestCaseRetrieveResponse"] - - -class TestCaseRetrieveResponse(BaseModel): - __test__ = False - id: str - """测试样例 ID""" - - ats_id: str - """所属的测试集 ID""" - - created_at: datetime - """创建时间""" - - expected_sql: str - """用户期望生成的 sql""" - - modified_at: datetime - """修改时间""" - - question: str - """用户提问""" - - role_id: Optional[str] = None - """角色 ID""" - - role_variables: Optional[object] = None - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" diff --git a/src/asktable/types/ats/test_case_update_params.py b/src/asktable/types/ats/test_case_update_params.py deleted file mode 100644 index 020118e0..00000000 --- a/src/asktable/types/ats/test_case_update_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -__all__ = ["TestCaseUpdateParams"] - - -class TestCaseUpdateParams(TypedDict, total=False): - ats_id: Required[str] - - expected_sql: Required[str] - """用户期望生成的 sql""" - - question: Required[str] - """用户提问""" - - role_id: Optional[str] - """角色 ID""" - - role_variables: Optional[object] - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" diff --git a/src/asktable/types/ats/test_case_update_response.py b/src/asktable/types/ats/test_case_update_response.py deleted file mode 100644 index 089d55e8..00000000 --- a/src/asktable/types/ats/test_case_update_response.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["TestCaseUpdateResponse"] - - -class TestCaseUpdateResponse(BaseModel): - __test__ = False - id: str - """测试样例 ID""" - - ats_id: str - """所属的测试集 ID""" - - created_at: datetime - """创建时间""" - - expected_sql: str - """用户期望生成的 sql""" - - modified_at: datetime - """修改时间""" - - question: str - """用户提问""" - - role_id: Optional[str] = None - """角色 ID""" - - role_variables: Optional[object] = None - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" diff --git a/src/asktable/types/ats_create_params.py b/src/asktable/types/ats_create_params.py deleted file mode 100644 index 64ea530f..00000000 --- a/src/asktable/types/ats_create_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ATSCreateParams"] - - -class ATSCreateParams(TypedDict, total=False): - datasource_id: Required[str] - """该测试集对应数据源的 ID""" - - name: Required[str] - """测试集名称""" diff --git a/src/asktable/types/ats_create_response.py b/src/asktable/types/ats_create_response.py deleted file mode 100644 index 4ed69a97..00000000 --- a/src/asktable/types/ats_create_response.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["ATSCreateResponse"] - - -class ATSCreateResponse(BaseModel): - id: str - """测试集的 ID""" - - created_at: datetime - """测试集的创建时间""" - - datasource_id: str - """该测试集对应数据源的 ID""" - - modified_at: datetime - """测试集的修改时间""" - - name: str - """测试集名称""" - - project_id: str - """项目 ID""" diff --git a/src/asktable/types/ats_delete_params.py b/src/asktable/types/ats_delete_params.py deleted file mode 100644 index e8eef511..00000000 --- a/src/asktable/types/ats_delete_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ATSDeleteParams"] - - -class ATSDeleteParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" diff --git a/src/asktable/types/ats_list_params.py b/src/asktable/types/ats_list_params.py deleted file mode 100644 index 09110362..00000000 --- a/src/asktable/types/ats_list_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ATSListParams"] - - -class ATSListParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" - - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/ats_list_response.py b/src/asktable/types/ats_list_response.py deleted file mode 100644 index 04206289..00000000 --- a/src/asktable/types/ats_list_response.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["ATSListResponse"] - - -class ATSListResponse(BaseModel): - id: str - """测试集的 ID""" - - created_at: datetime - """测试集的创建时间""" - - datasource_id: str - """该测试集对应数据源的 ID""" - - modified_at: datetime - """测试集的修改时间""" - - name: str - """测试集名称""" - - project_id: str - """项目 ID""" diff --git a/src/asktable/types/ats_retrieve_response.py b/src/asktable/types/ats_retrieve_response.py deleted file mode 100644 index 0195c97c..00000000 --- a/src/asktable/types/ats_retrieve_response.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["ATSRetrieveResponse"] - - -class ATSRetrieveResponse(BaseModel): - id: str - """测试集的 ID""" - - created_at: datetime - """测试集的创建时间""" - - datasource_id: str - """该测试集对应数据源的 ID""" - - modified_at: datetime - """测试集的修改时间""" - - name: str - """测试集名称""" - - project_id: str - """项目 ID""" diff --git a/src/asktable/types/ats_update_params.py b/src/asktable/types/ats_update_params.py deleted file mode 100644 index 3b1cdbba..00000000 --- a/src/asktable/types/ats_update_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ATSUpdateParams"] - - -class ATSUpdateParams(TypedDict, total=False): - name: Required[str] - """测试集更新的名字""" diff --git a/src/asktable/types/ats_update_response.py b/src/asktable/types/ats_update_response.py deleted file mode 100644 index 374dfe87..00000000 --- a/src/asktable/types/ats_update_response.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["ATSUpdateResponse"] - - -class ATSUpdateResponse(BaseModel): - id: str - """测试集的 ID""" - - created_at: datetime - """测试集的创建时间""" - - datasource_id: str - """该测试集对应数据源的 ID""" - - modified_at: datetime - """测试集的修改时间""" - - name: str - """测试集名称""" - - project_id: str - """项目 ID""" diff --git a/src/asktable/types/auth_create_token_params.py b/src/asktable/types/auth_create_token_params.py index 7764745b..62aab155 100644 --- a/src/asktable/types/auth_create_token_params.py +++ b/src/asktable/types/auth_create_token_params.py @@ -2,14 +2,14 @@ from __future__ import annotations -from typing import Optional +from typing import Dict, Optional from typing_extensions import Literal, TypedDict __all__ = ["AuthCreateTokenParams", "ChatRole"] class AuthCreateTokenParams(TypedDict, total=False): - ak_role: Literal["sys", "admin", "asker", "visitor"] + ak_role: Literal["sys", "admin", "asker"] """The role for the API key""" chat_role: Optional[ChatRole] @@ -18,13 +18,15 @@ class AuthCreateTokenParams(TypedDict, total=False): token_ttl: int """The time-to-live for the token in seconds""" - user_profile: Optional[object] + user_profile: Optional[Dict[str, object]] """Optional user profile data""" class ChatRole(TypedDict, total=False): + """The chat role""" + role_id: Optional[str] """The chat role ID""" - role_variables: Optional[object] + role_variables: Optional[Dict[str, object]] """The chat role variables""" diff --git a/src/asktable/types/auth_create_token_response.py b/src/asktable/types/auth_create_token_response.py new file mode 100644 index 00000000..0ff7ae33 --- /dev/null +++ b/src/asktable/types/auth_create_token_response.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["AuthCreateTokenResponse"] + +AuthCreateTokenResponse: TypeAlias = Dict[str, object] diff --git a/src/asktable/types/auth_me_response.py b/src/asktable/types/auth_me_response.py index 0db427fa..02bc3c2a 100644 --- a/src/asktable/types/auth_me_response.py +++ b/src/asktable/types/auth_me_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, Optional from typing_extensions import Literal from .._models import BaseModel @@ -9,16 +9,16 @@ class AuthMeResponse(BaseModel): - ak_role: Literal["sys", "admin", "asker", "visitor"] + ak_role: Literal["sys", "admin", "asker"] project_id: str ak_id: Optional[str] = None - chat_role: Optional[object] = None + chat_role: Optional[Dict[str, object]] = None exp: Optional[int] = None locked: Optional[bool] = None - user_profile: Optional[object] = None + user_profile: Optional[Dict[str, object]] = None diff --git a/src/asktable/types/bot_create_params.py b/src/asktable/types/bot_create_params.py deleted file mode 100644 index e2a2f550..00000000 --- a/src/asktable/types/bot_create_params.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["BotCreateParams", "InteractionRule"] - - -class BotCreateParams(TypedDict, total=False): - datasource_ids: Required[List[str]] - """数据源 ID,目前只支持 1 个数据源。""" - - name: Required[str] - """名称,不超过 64 个字符""" - - color_theme: Optional[str] - """颜色主题""" - - debug: bool - """调试模式""" - - extapi_ids: List[str] - """扩展 API ID 列表,扩展 API ID 的逗号分隔列表。""" - - interaction_rules: Iterable[InteractionRule] - """交互规则列表,用于定义 bot 的行为规则""" - - magic_input: Optional[str] - """魔法提示词""" - - max_rows: int - """最大返回行数,默认不限制""" - - publish: bool - """是否公开""" - - query_balance: Optional[int] - """bot 的查询次数,默认是 None,表示无限次查询,入参为大于等于 0 的整数""" - - sample_questions: Optional[List[str]] - """示例问题列表""" - - webhooks: List[str] - """Webhook URL 列表""" - - welcome_message: Optional[str] - """欢迎消息""" - - -class InteractionRule(TypedDict, total=False): - enabled: Required[bool] - - message: Required[str] - - name: Required[str] - - version: Required[Literal["1.0.0"]] - - words: Required[List[str]] diff --git a/src/asktable/types/bot_invite_params.py b/src/asktable/types/bot_invite_params.py deleted file mode 100644 index 0e85f7e0..00000000 --- a/src/asktable/types/bot_invite_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["BotInviteParams"] - - -class BotInviteParams(TypedDict, total=False): - project_id: Required[str] diff --git a/src/asktable/types/bot_list_params.py b/src/asktable/types/bot_list_params.py deleted file mode 100644 index 2463c813..00000000 --- a/src/asktable/types/bot_list_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from typing_extensions import TypedDict - -__all__ = ["BotListParams"] - - -class BotListParams(TypedDict, total=False): - bot_ids: Optional[List[str]] - """Bot ID""" - - name: Optional[str] - """名称""" - - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/bot_update_params.py b/src/asktable/types/bot_update_params.py deleted file mode 100644 index e08d5a37..00000000 --- a/src/asktable/types/bot_update_params.py +++ /dev/null @@ -1,64 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["BotUpdateParams", "InteractionRule"] - - -class BotUpdateParams(TypedDict, total=False): - avatar_url: Optional[str] - """头像 URL""" - - color_theme: Optional[str] - """颜色主题""" - - datasource_ids: Optional[List[str]] - """数据源 ID,目前只支持 1 个数据源。""" - - debug: Optional[bool] - """调试模式""" - - extapi_ids: Optional[List[str]] - """扩展 API ID 列表,扩展 API ID 的逗号分隔列表。""" - - interaction_rules: Optional[Iterable[InteractionRule]] - """交互规则列表,用于定义 bot 的行为规则""" - - magic_input: Optional[str] - """魔法提示词""" - - max_rows: Optional[int] - """最大返回行数,默认不限制""" - - name: Optional[str] - """名称,不超过 64 个字符""" - - publish: Optional[bool] - """是否公开""" - - query_balance: Optional[int] - """bot 的查询次数,默认是 None,表示无限次查询,入参为大于等于 0 的整数""" - - sample_questions: Optional[List[str]] - """示例问题列表""" - - webhooks: Optional[List[str]] - """Webhook URL 列表""" - - welcome_message: Optional[str] - """欢迎消息""" - - -class InteractionRule(TypedDict, total=False): - enabled: Required[bool] - - message: Required[str] - - name: Required[str] - - version: Required[Literal["1.0.0"]] - - words: Required[List[str]] diff --git a/src/asktable/types/business_glossary_create_params.py b/src/asktable/types/business_glossary_create_params.py deleted file mode 100644 index e9f3d42d..00000000 --- a/src/asktable/types/business_glossary_create_params.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Iterable, Optional -from typing_extensions import Required, TypedDict - -__all__ = ["BusinessGlossaryCreateParams", "Body"] - - -class BusinessGlossaryCreateParams(TypedDict, total=False): - body: Required[Iterable[Body]] - - -class Body(TypedDict, total=False): - definition: Required[str] - """业务术语定义""" - - term: Required[str] - """业务术语""" - - active: bool - """业务术语是否生效""" - - aliases: Optional[List[str]] - """业务术语同义词""" - - payload: Optional[object] - """业务术语元数据""" diff --git a/src/asktable/types/business_glossary_create_response.py b/src/asktable/types/business_glossary_create_response.py deleted file mode 100644 index 2b908192..00000000 --- a/src/asktable/types/business_glossary_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import TypeAlias - -from .entry import Entry - -__all__ = ["BusinessGlossaryCreateResponse"] - -BusinessGlossaryCreateResponse: TypeAlias = List[Entry] diff --git a/src/asktable/types/business_glossary_list_params.py b/src/asktable/types/business_glossary_list_params.py deleted file mode 100644 index b7753d3c..00000000 --- a/src/asktable/types/business_glossary_list_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["BusinessGlossaryListParams"] - - -class BusinessGlossaryListParams(TypedDict, total=False): - page: int - """Page number""" - - size: int - """Page size""" - - term: str - """术语名称""" diff --git a/src/asktable/types/business_glossary_update_params.py b/src/asktable/types/business_glossary_update_params.py deleted file mode 100644 index 89bad224..00000000 --- a/src/asktable/types/business_glossary_update_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from typing_extensions import TypedDict - -__all__ = ["BusinessGlossaryUpdateParams"] - - -class BusinessGlossaryUpdateParams(TypedDict, total=False): - active: Optional[bool] - """业务术语是否生效""" - - aliases: Optional[List[str]] - """业务术语同义词""" - - definition: Optional[str] - """业务术语定义""" - - payload: Optional[object] - """业务术语元数据""" - - term: Optional[str] - """业务术语""" diff --git a/src/asktable/types/chat.py b/src/asktable/types/chat.py deleted file mode 100644 index ff282d79..00000000 --- a/src/asktable/types/chat.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Union, Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["Chat"] - - -class Chat(BaseModel): - id: str - """对话 ID""" - - created_at: datetime - """创建时间""" - - modified_at: datetime - """修改时间""" - - project_id: str - - status: Literal["active", "pending", "error", "fatal"] - - status_message: Optional[str] = None - - bot_id: Optional[str] = None - """ - 机器人 ID,如果需要使用高级功能,请使用 bot_id 来创建对话。在机器人中你可以定义 - 可以访问的数据、可以执行的任务以及是否开启调试模式等设置。 - """ - - name: Optional[str] = None - """New name for the chat""" - - role_id: Optional[str] = None - """ - 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - """ - - role_variables: Optional[Dict[str, Union[str, int, bool]]] = None - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" - - user_profile: Optional[Dict[str, Union[str, int, bool]]] = None - """用户信息,用于在对话中传递用户的信息,用 Key-Value 形式传递""" diff --git a/src/asktable/types/chat_create_params.py b/src/asktable/types/chat_create_params.py deleted file mode 100644 index ca697335..00000000 --- a/src/asktable/types/chat_create_params.py +++ /dev/null @@ -1,31 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional -from typing_extensions import TypedDict - -__all__ = ["ChatCreateParams"] - - -class ChatCreateParams(TypedDict, total=False): - bot_id: Optional[str] - """ - 机器人 ID,如果需要使用高级功能,请使用 bot_id 来创建对话。在机器人中你可以定义 - 可以访问的数据、可以执行的任务以及是否开启调试模式等设置。 - """ - - name: Optional[str] - """New name for the chat""" - - role_id: Optional[str] - """ - 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - """ - - role_variables: Optional[Dict[str, Union[str, int, bool]]] - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" - - user_profile: Optional[Dict[str, Union[str, int, bool]]] - """用户信息,用于在对话中传递用户的信息,用 Key-Value 形式传递""" diff --git a/src/asktable/types/chat_list_params.py b/src/asktable/types/chat_list_params.py deleted file mode 100644 index 5a0964bc..00000000 --- a/src/asktable/types/chat_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["ChatListParams"] - - -class ChatListParams(TypedDict, total=False): - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/chat_retrieve_response.py b/src/asktable/types/chat_retrieve_response.py deleted file mode 100644 index 3868c1a8..00000000 --- a/src/asktable/types/chat_retrieve_response.py +++ /dev/null @@ -1,53 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ChatRetrieveResponse"] - - -class ChatRetrieveResponse(BaseModel): - id: str - """对话 ID""" - - created_at: datetime - """创建时间""" - - modified_at: datetime - """修改时间""" - - project_id: str - - status: Literal["active", "pending", "error", "fatal"] - - status_message: Optional[str] = None - - bot_id: Optional[str] = None - """ - 机器人 ID,如果需要使用高级功能,请使用 bot_id 来创建对话。在机器人中你可以定义 - 可以访问的数据、可以执行的任务以及是否开启调试模式等设置。 - """ - - datasource_ids: Optional[List[str]] = None - - name: Optional[str] = None - """New name for the chat""" - - role_id: Optional[str] = None - """ - 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - """ - - role_variables: Optional[Dict[str, Union[str, int, bool]]] = None - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" - - sample_questions: Optional[List[str]] = None - - user_profile: Optional[Dict[str, Union[str, int, bool]]] = None - """用户信息,用于在对话中传递用户的信息,用 Key-Value 形式传递""" - - welcome_message: Optional[str] = None diff --git a/src/asktable/types/chatbot.py b/src/asktable/types/chatbot.py deleted file mode 100644 index 2c37b41b..00000000 --- a/src/asktable/types/chatbot.py +++ /dev/null @@ -1,73 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["Chatbot", "InteractionRule"] - - -class InteractionRule(BaseModel): - enabled: bool - - message: str - - name: str - - version: Literal["1.0.0"] - - words: List[str] - - -class Chatbot(BaseModel): - id: str - - created_at: datetime - - datasource_ids: List[str] - """数据源 ID,目前只支持 1 个数据源。""" - - modified_at: datetime - - name: str - """名称,不超过 64 个字符""" - - project_id: str - - avatar_url: Optional[str] = None - """头像 URL""" - - color_theme: Optional[str] = None - """颜色主题""" - - debug: Optional[bool] = None - """调试模式""" - - extapi_ids: Optional[List[str]] = None - """扩展 API ID 列表,扩展 API ID 的逗号分隔列表。""" - - interaction_rules: Optional[List[InteractionRule]] = None - """交互规则列表,用于定义 bot 的行为规则""" - - magic_input: Optional[str] = None - """魔法提示词""" - - max_rows: Optional[int] = None - """最大返回行数,默认不限制""" - - publish: Optional[bool] = None - """是否公开""" - - query_balance: Optional[int] = None - """bot 的查询次数,默认是 None,表示无限次查询,入参为大于等于 1 的整数""" - - sample_questions: Optional[List[str]] = None - """示例问题列表""" - - webhooks: Optional[List[str]] = None - """Webhook URL 列表""" - - welcome_message: Optional[str] = None - """欢迎消息""" diff --git a/src/asktable/types/chats/__init__.py b/src/asktable/types/chats/__init__.py index 0000314b..f8ee8b14 100644 --- a/src/asktable/types/chats/__init__.py +++ b/src/asktable/types/chats/__init__.py @@ -1,9 +1,3 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from __future__ import annotations - -from .message_list_params import MessageListParams as MessageListParams -from .message_create_params import MessageCreateParams as MessageCreateParams -from .message_list_response import MessageListResponse as MessageListResponse -from .message_create_response import MessageCreateResponse as MessageCreateResponse -from .message_retrieve_response import MessageRetrieveResponse as MessageRetrieveResponse diff --git a/src/asktable/types/chats/message_create_params.py b/src/asktable/types/chats/message_create_params.py deleted file mode 100644 index 64600d94..00000000 --- a/src/asktable/types/chats/message_create_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["MessageCreateParams"] - - -class MessageCreateParams(TypedDict, total=False): - question: Required[str] diff --git a/src/asktable/types/chats/message_create_response.py b/src/asktable/types/chats/message_create_response.py deleted file mode 100644 index 3cf2a0ba..00000000 --- a/src/asktable/types/chats/message_create_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import TypeAlias - -from ..ai_message import AIMessage -from ..tool_message import ToolMessage -from ..user_message import UserMessage - -__all__ = ["MessageCreateResponse"] - -MessageCreateResponse: TypeAlias = Union[UserMessage, AIMessage, ToolMessage] diff --git a/src/asktable/types/chats/message_list_params.py b/src/asktable/types/chats/message_list_params.py deleted file mode 100644 index 2d21dd57..00000000 --- a/src/asktable/types/chats/message_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["MessageListParams"] - - -class MessageListParams(TypedDict, total=False): - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/chats/message_list_response.py b/src/asktable/types/chats/message_list_response.py deleted file mode 100644 index 95be2a20..00000000 --- a/src/asktable/types/chats/message_list_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import TypeAlias - -from ..ai_message import AIMessage -from ..tool_message import ToolMessage -from ..user_message import UserMessage - -__all__ = ["MessageListResponse"] - -MessageListResponse: TypeAlias = Union[UserMessage, AIMessage, ToolMessage] diff --git a/src/asktable/types/chats/message_retrieve_response.py b/src/asktable/types/chats/message_retrieve_response.py deleted file mode 100644 index c19db35e..00000000 --- a/src/asktable/types/chats/message_retrieve_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import TypeAlias - -from ..ai_message import AIMessage -from ..tool_message import ToolMessage -from ..user_message import UserMessage - -__all__ = ["MessageRetrieveResponse"] - -MessageRetrieveResponse: TypeAlias = Union[UserMessage, AIMessage, ToolMessage] diff --git a/src/asktable/types/dataframe_retrieve_response.py b/src/asktable/types/dataframe_retrieve_response.py index 75cdbde6..56619d43 100644 --- a/src/asktable/types/dataframe_retrieve_response.py +++ b/src/asktable/types/dataframe_retrieve_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import Dict, List, Optional from datetime import datetime from .._models import BaseModel @@ -12,24 +12,18 @@ class DataframeRetrieveResponse(BaseModel): id: str """ID""" - chart_options: object + chart_options: Dict[str, object] """图表选项""" - content: List[object] - """内容""" - created_at: datetime """创建时间""" - header: List[object] + header: List[Dict[str, object]] """表头""" modified_at: datetime """更新时间""" - msg_id: str - """消息 ID""" - project_id: str """项目 ID""" @@ -41,3 +35,12 @@ class DataframeRetrieveResponse(BaseModel): title: str """标题""" + + chart_config: Optional[Dict[str, object]] = None + """ChartSpec 图表配置""" + + content: Optional[List[Dict[str, object]]] = None + """内容""" + + msg_id: Optional[str] = None + """消息 ID""" diff --git a/src/asktable/types/datasource.py b/src/asktable/types/datasource.py index 70a1ae18..4b97e17f 100644 --- a/src/asktable/types/datasource.py +++ b/src/asktable/types/datasource.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal @@ -38,11 +38,25 @@ class Datasource(BaseModel): "databend", "sqlserver", "mogdb", + "hologres", + "maxcompute", + "gaussdb", + "tdsqlmysql", + "tdsqlpg", + "kingbasees", + "gbase8c", + "yashandb", + "gbase8a", + "gaussdbdws", + "bitable", + "dap", + "duckdb", + "workbook", ] """数据源引擎""" - meta_status: Literal["processing", "failed", "success", "unprocessed"] - """元数据处理状态""" + meta_status: Literal["unavailable", "available"] + """数据源可用性""" modified_at: datetime """修改时间""" @@ -50,23 +64,29 @@ class Datasource(BaseModel): project_id: str """项目 ID""" + sync_status: Literal["processing", "success", "failed", "warning"] + """同步状态""" + desc: Optional[str] = None """数据源描述""" field_count: Optional[int] = None """字段数量""" - meta_error: Optional[str] = None - """元数据处理错误""" - name: Optional[str] = None """数据源的名称""" - sample_questions: Optional[str] = None + sample_questions: Optional[List[str]] = None """示例问题""" schema_count: Optional[int] = None """库数量""" + sync_error: Optional[Dict[str, object]] = None + """同步错误信息""" + + synced_at: Optional[datetime] = None + """上次同步完成时间""" + table_count: Optional[int] = None """表数量""" diff --git a/src/asktable/types/datasource_add_file_params.py b/src/asktable/types/datasource_add_file_params.py index fa03fb7a..39418d4a 100644 --- a/src/asktable/types/datasource_add_file_params.py +++ b/src/asktable/types/datasource_add_file_params.py @@ -4,10 +4,8 @@ from typing_extensions import Required, TypedDict -from .._types import FileTypes - __all__ = ["DatasourceAddFileParams"] class DatasourceAddFileParams(TypedDict, total=False): - file: Required[FileTypes] + file: Required[str] diff --git a/src/asktable/types/datasource_create_params.py b/src/asktable/types/datasource_create_params.py index afd362b0..01b77af5 100644 --- a/src/asktable/types/datasource_create_params.py +++ b/src/asktable/types/datasource_create_params.py @@ -2,14 +2,17 @@ from __future__ import annotations -from typing import List, Union, Optional +from typing import Dict, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from .._types import SequenceNotStr + __all__ = [ "DatasourceCreateParams", "AccessConfig", "AccessConfigAccessConfigConnectionCreate", "AccessConfigAccessConfigFileCreate", + "AccessConfigAccessConfigWorkbookCreate", ] @@ -37,6 +40,20 @@ class DatasourceCreateParams(TypedDict, total=False): "databend", "sqlserver", "mogdb", + "hologres", + "maxcompute", + "gaussdb", + "tdsqlmysql", + "tdsqlpg", + "kingbasees", + "gbase8c", + "yashandb", + "gbase8a", + "gaussdbdws", + "bitable", + "dap", + "duckdb", + "workbook", ] ] """数据源引擎""" @@ -58,7 +75,7 @@ class AccessConfigAccessConfigConnectionCreate(TypedDict, total=False): db_version: Optional[str] """数据库版本""" - extra_config: Optional[object] + extra_config: Optional[Dict[str, object]] """额外配置""" password: Optional[str] @@ -75,8 +92,17 @@ class AccessConfigAccessConfigConnectionCreate(TypedDict, total=False): class AccessConfigAccessConfigFileCreate(TypedDict, total=False): - files: Required[List[str]] + files: Required[SequenceNotStr[str]] """数据源文件 URL 列表, 创建时可以传入 URL""" -AccessConfig: TypeAlias = Union[AccessConfigAccessConfigConnectionCreate, AccessConfigAccessConfigFileCreate] +class AccessConfigAccessConfigWorkbookCreate(TypedDict, total=False): + """workbook 创建时前端不传 workbook_id,flow 用 datasource_id 填充。""" + + workbook_id: Optional[str] + """workbook 标识,等于 datasource_id;创建时由 flow 分配""" + + +AccessConfig: TypeAlias = Union[ + AccessConfigAccessConfigConnectionCreate, AccessConfigAccessConfigFileCreate, AccessConfigAccessConfigWorkbookCreate +] diff --git a/src/asktable/types/datasource_retrieve_response.py b/src/asktable/types/datasource_retrieve_response.py index d244225c..5cc714de 100644 --- a/src/asktable/types/datasource_retrieve_response.py +++ b/src/asktable/types/datasource_retrieve_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from datetime import datetime from typing_extensions import Literal, TypeAlias @@ -12,6 +12,7 @@ "AccessConfigAccessConfigConnectionResponse", "AccessConfigAccessConfigFileResponse", "AccessConfigAccessConfigFileResponseFile", + "AccessConfigAccessConfigWorkbookResponse", ] @@ -28,7 +29,7 @@ class AccessConfigAccessConfigConnectionResponse(BaseModel): db_version: Optional[str] = None """数据库版本""" - extra_config: Optional[object] = None + extra_config: Optional[Dict[str, object]] = None """额外配置""" port: Optional[int] = None @@ -52,7 +53,7 @@ class AccessConfigAccessConfigFileResponseFile(BaseModel): filename: str - custom_config: Optional[object] = None + custom_config: Optional[Dict[str, object]] = None """文件自定义配置""" @@ -61,7 +62,17 @@ class AccessConfigAccessConfigFileResponse(BaseModel): """数据源文件 ID 列表""" -AccessConfig: TypeAlias = Union[AccessConfigAccessConfigConnectionResponse, AccessConfigAccessConfigFileResponse, None] +class AccessConfigAccessConfigWorkbookResponse(BaseModel): + workbook_id: Optional[str] = None + """workbook 标识,等于 datasource_id;创建时由 flow 分配""" + + +AccessConfig: TypeAlias = Union[ + AccessConfigAccessConfigConnectionResponse, + AccessConfigAccessConfigFileResponse, + AccessConfigAccessConfigWorkbookResponse, + None, +] class DatasourceRetrieveResponse(BaseModel): @@ -93,11 +104,25 @@ class DatasourceRetrieveResponse(BaseModel): "databend", "sqlserver", "mogdb", + "hologres", + "maxcompute", + "gaussdb", + "tdsqlmysql", + "tdsqlpg", + "kingbasees", + "gbase8c", + "yashandb", + "gbase8a", + "gaussdbdws", + "bitable", + "dap", + "duckdb", + "workbook", ] """数据源引擎""" - meta_status: Literal["processing", "failed", "success", "unprocessed"] - """元数据处理状态""" + meta_status: Literal["unavailable", "available"] + """数据源可用性""" modified_at: datetime """修改时间""" @@ -105,6 +130,9 @@ class DatasourceRetrieveResponse(BaseModel): project_id: str """项目 ID""" + sync_status: Literal["processing", "success", "failed", "warning"] + """同步状态""" + access_config: Optional[AccessConfig] = None """访问数据源的配置信息""" @@ -114,17 +142,20 @@ class DatasourceRetrieveResponse(BaseModel): field_count: Optional[int] = None """字段数量""" - meta_error: Optional[str] = None - """元数据处理错误""" - name: Optional[str] = None """数据源的名称""" - sample_questions: Optional[str] = None + sample_questions: Optional[List[str]] = None """示例问题""" schema_count: Optional[int] = None """库数量""" + sync_error: Optional[Dict[str, object]] = None + """同步错误信息""" + + synced_at: Optional[datetime] = None + """上次同步完成时间""" + table_count: Optional[int] = None """表数量""" diff --git a/src/asktable/types/datasource_update_params.py b/src/asktable/types/datasource_update_params.py index ff22daff..e6c5d1bf 100644 --- a/src/asktable/types/datasource_update_params.py +++ b/src/asktable/types/datasource_update_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from .._types import SequenceNotStr + __all__ = [ "DatasourceUpdateParams", "AccessConfig", @@ -44,6 +46,20 @@ class DatasourceUpdateParams(TypedDict, total=False): "databend", "sqlserver", "mogdb", + "hologres", + "maxcompute", + "gaussdb", + "tdsqlmysql", + "tdsqlpg", + "kingbasees", + "gbase8c", + "yashandb", + "gbase8a", + "gaussdbdws", + "bitable", + "dap", + "duckdb", + "workbook", ] ] """数据源引擎""" @@ -51,21 +67,24 @@ class DatasourceUpdateParams(TypedDict, total=False): field_count: Optional[int] """字段数量""" - meta_error: Optional[str] - """元数据处理错误""" - - meta_status: Optional[Literal["processing", "failed", "success", "unprocessed"]] - """元数据处理状态""" + meta_status: Optional[Literal["unavailable", "available"]] + """数据源可用性""" name: Optional[str] """数据源的名称""" - sample_questions: Optional[str] + sample_questions: Optional[SequenceNotStr[str]] """示例问题""" schema_count: Optional[int] """库数量""" + sync_error: Optional[Dict[str, object]] + """同步错误信息""" + + sync_status: Optional[Literal["processing", "success", "failed", "warning"]] + """同步状态""" + table_count: Optional[int] """表数量""" @@ -77,7 +96,7 @@ class AccessConfigAccessConfigConnectionUpdate(TypedDict, total=False): db_version: Optional[str] """数据库版本""" - extra_config: Optional[object] + extra_config: Optional[Dict[str, object]] """额外配置""" host: Optional[str] @@ -101,7 +120,7 @@ class AccessConfigAccessConfigFileUpdateFile(TypedDict, total=False): filename: Required[str] - custom_config: Optional[object] + custom_config: Optional[Dict[str, object]] """文件自定义配置""" diff --git a/src/asktable/types/datasources/__init__.py b/src/asktable/types/datasources/__init__.py index b015a299..a36de7e7 100644 --- a/src/asktable/types/datasources/__init__.py +++ b/src/asktable/types/datasources/__init__.py @@ -8,3 +8,4 @@ from .index_create_params import IndexCreateParams as IndexCreateParams from .meta_annotate_params import MetaAnnotateParams as MetaAnnotateParams from .upload_param_create_params import UploadParamCreateParams as UploadParamCreateParams +from .upload_param_create_response import UploadParamCreateResponse as UploadParamCreateResponse diff --git a/src/asktable/types/datasources/meta_create_params.py b/src/asktable/types/datasources/meta_create_params.py index 86783588..10f3ac13 100644 --- a/src/asktable/types/datasources/meta_create_params.py +++ b/src/asktable/types/datasources/meta_create_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Dict, List, Optional +from typing import Dict, Optional from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["MetaCreateParams", "Meta", "MetaSchemas", "MetaSchemasTables", "MetaSchemasTablesFields"] @@ -15,7 +17,7 @@ class MetaCreateParams(TypedDict, total=False): meta: Optional[Meta] - selected_tables: Optional[Dict[str, List[str]]] + selected_tables: Optional[Dict[str, SequenceNotStr[str]]] class MetaSchemasTablesFields(TypedDict, total=False): @@ -58,7 +60,7 @@ class MetaSchemas(TypedDict, total=False): origin_desc: Required[str] """schema description from database""" - custom_configs: Optional[object] + custom_configs: Optional[Dict[str, object]] """custom configs""" tables: Dict[str, MetaSchemasTables] diff --git a/src/asktable/types/datasources/meta_update_params.py b/src/asktable/types/datasources/meta_update_params.py index 2a14b685..dc0d45fa 100644 --- a/src/asktable/types/datasources/meta_update_params.py +++ b/src/asktable/types/datasources/meta_update_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Dict, List, Optional +from typing import Dict, Optional from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["MetaUpdateParams", "Meta", "MetaSchemas", "MetaSchemasTables", "MetaSchemasTablesFields"] @@ -13,7 +15,7 @@ class MetaUpdateParams(TypedDict, total=False): meta: Optional[Meta] - selected_tables: Optional[Dict[str, List[str]]] + selected_tables: Optional[Dict[str, SequenceNotStr[str]]] class MetaSchemasTablesFields(TypedDict, total=False): @@ -56,7 +58,7 @@ class MetaSchemas(TypedDict, total=False): origin_desc: Required[str] """schema description from database""" - custom_configs: Optional[object] + custom_configs: Optional[Dict[str, object]] """custom configs""" tables: Dict[str, MetaSchemasTables] diff --git a/src/asktable/types/datasources/upload_param_create_response.py b/src/asktable/types/datasources/upload_param_create_response.py new file mode 100644 index 00000000..eec09f23 --- /dev/null +++ b/src/asktable/types/datasources/upload_param_create_response.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["UploadParamCreateResponse"] + +UploadParamCreateResponse: TypeAlias = Dict[str, object] diff --git a/src/asktable/types/entry.py b/src/asktable/types/entry.py deleted file mode 100644 index a4140a5d..00000000 --- a/src/asktable/types/entry.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["Entry"] - - -class Entry(BaseModel): - id: str - """业务术语 ID""" - - created_at: datetime - """创建时间""" - - modified_at: datetime - """更新时间""" - - project_id: str - """项目 ID""" - - term: str - """业务术语""" - - active: Optional[bool] = None - """业务术语是否生效""" - - aliases: Optional[List[str]] = None - """业务术语同义词""" - - payload: Optional[object] = None - """业务术语元数据""" diff --git a/src/asktable/types/entry_with_definition.py b/src/asktable/types/entry_with_definition.py deleted file mode 100644 index 9b76baff..00000000 --- a/src/asktable/types/entry_with_definition.py +++ /dev/null @@ -1,37 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["EntryWithDefinition"] - - -class EntryWithDefinition(BaseModel): - id: str - """业务术语 ID""" - - created_at: datetime - """创建时间""" - - definition: str - """业务术语定义""" - - modified_at: datetime - """更新时间""" - - project_id: str - """项目 ID""" - - term: str - """业务术语""" - - active: Optional[bool] = None - """业务术语是否生效""" - - aliases: Optional[List[str]] = None - """业务术语同义词""" - - payload: Optional[object] = None - """业务术语元数据""" diff --git a/src/asktable/types/file_ask_response.py b/src/asktable/types/file_ask_response.py deleted file mode 100644 index bbf7f554..00000000 --- a/src/asktable/types/file_ask_response.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel -from .datasource import Datasource -from .answer_response import AnswerResponse - -__all__ = ["FileAskResponse"] - - -class FileAskResponse(BaseModel): - answer: AnswerResponse - - datasource: Datasource diff --git a/src/asktable/types/index.py b/src/asktable/types/index.py index a558c037..ea46e49f 100644 --- a/src/asktable/types/index.py +++ b/src/asktable/types/index.py @@ -9,6 +9,8 @@ class Index(BaseModel): + """索引响应模型""" + id: str """索引 ID""" diff --git a/src/asktable/types/integration_create_excel_ds_params.py b/src/asktable/types/integration_create_excel_ds_params.py deleted file mode 100644 index 05e3e2fa..00000000 --- a/src/asktable/types/integration_create_excel_ds_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["IntegrationCreateExcelDsParams"] - - -class IntegrationCreateExcelDsParams(TypedDict, total=False): - file_url: Required[str] - - value_index: bool diff --git a/src/asktable/types/meta.py b/src/asktable/types/meta.py index f94d2037..b3442c15 100644 --- a/src/asktable/types/meta.py +++ b/src/asktable/types/meta.py @@ -6,7 +6,26 @@ from .._models import BaseModel -__all__ = ["Meta", "Schemas", "SchemasTables", "SchemasTablesFields"] +__all__ = ["Meta", "Schemas", "SchemasTables", "SchemasTablesFields", "SchemasTablesFieldsIndex"] + + +class SchemasTablesFieldsIndex(BaseModel): + """索引信息""" + + id: str + """索引 ID""" + + distinct_count: Optional[int] = None + """不同值数量""" + + index_value_count: Optional[int] = None + """索引值总数""" + + status_msg: Optional[str] = None + """状态信息,为空表示成功""" + + value_count: Optional[int] = None + """值总数""" class SchemasTablesFields(BaseModel): @@ -39,6 +58,9 @@ class SchemasTablesFields(BaseModel): ] = None """identifiable type""" + index: Optional[SchemasTablesFieldsIndex] = None + """索引信息""" + sample_data: Optional[str] = None """field sample data""" @@ -83,7 +105,7 @@ class Schemas(BaseModel): tables: Dict[str, SchemasTables] - custom_configs: Optional[object] = None + custom_configs: Optional[Dict[str, object]] = None """custom configs""" diff --git a/src/asktable/types/policy_create_params.py b/src/asktable/types/policy_create_params.py deleted file mode 100644 index 9630207c..00000000 --- a/src/asktable/types/policy_create_params.py +++ /dev/null @@ -1,93 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["PolicyCreateParams", "DatasetConfig", "DatasetConfigRegexPatterns"] - - -class PolicyCreateParams(TypedDict, total=False): - dataset_config: Required[DatasetConfig] - """数据集配置""" - - name: Required[str] - """名称""" - - permission: Required[Literal["allow", "deny"]] - """权限""" - - -class DatasetConfigRegexPatterns(TypedDict, total=False): - fields_regex_pattern: Optional[str] - """Field 正则表达式,空值默认全选""" - - schemas_regex_pattern: Optional[str] - """Schema 正则表达式,空值默认全选""" - - tables_regex_pattern: Optional[str] - """Table 正则表达式,空值默认全选""" - - -class DatasetConfig(TypedDict, total=False): - datasource_ids: Required[List[str]] - """ - 数据源 ID 列表,必填。 - 描述:用于指定策略适用的数据源。可以使用通配符 _ 表示所 - 有数据源。 - 示例:["ds_id_1","ds_id_2"],["_"]。 - """ - - regex_patterns: Optional[DatasetConfigRegexPatterns] - """ - 正则表达式。 - 描述:用于匹配指定数据源中 Schema(DB)、Table 和 Field 名称的三 - 个正则表达式,即同时满足这三个正则表达式的 DB、Table 和 Field 才被允许访问。 - - 注意:此字段为可选项。如果未提供,则默认包含指定数据源的所有数据。 - """ - - rows_filters: Optional[Dict[str, List[str]]] - """行级别过滤器。 - - - 描述:指定行级别的过滤器,满足条件的行才可访问。 用户在查询数据的时候会自动对 - 结果集进行过滤,也同时会影响聚合计算(比如求 COUNT、SUM)的结果。 - - 格式: - - 按数据源组织,每个数据源对应一个过滤条件列表 `filter_condition` - - 每个 `filter_condition` 是一个字符串,格式为 - `".. "`。 - - 其中 `schema_name`、`table_name`、`field_name` 支持模糊匹配,比如支持 - `"*.*.*uid* = {{ user_id }}"`,来匹配所有包含 `uid` 的字段,且字段值等于 - `user_id` 的行。 - - 如何编写 `expression`: - - `expression` 中的操作符: - - 支持常见操作符:=, >, <, >=, <=, <>, !=, IN, NOT IN, LIKE, NOT LIKE, IS - NULL, IS NOT NULL - - `expression` 中的变量: - - 变量使用两个大括号括起来(支持 - [Jinja2](https://docs.jinkan.org/docs/jinja2/) 模版),比如 - {{user_id}},{{city_id}},{{merchant_id}} - - 变量的值需要在扮演角色时传递,全部使用字符串类型,比如 - "123","beijing","456" - - `expression` 中的函数: - - 支持内置函数 NOW() 获取当前时间,比如 "public.user.created_at > NOW() - 1 - YEAR" - - 数值、字符串、时间等字段的 `expression` 写法: - - 对于数值型、字符串类型的字段,可以直接填上常量或变量,都不用加引号,比如 - "public.user.age > {{age}}" ,"public.user.name = 张三 "或 - "public.user.name = {{name}} " - - 对于日期时间型字段 - - 使用单引号括起来的日期时间字符串进行过滤,比如 "public.user.created_at > - '2023-01-01 00:00:00 +00:00'" - - 使用变量时,需要使用大括号括起来,比如 "public.user.created_at > - {{start_date}}" - - 使用内置函数 NOW() 获取当前时间,比如 "public.user.created_at > NOW() - - 1 YEAR" - - 限制: - - 只允许当 permission = allow 时才可以设置该选项 - - 暂不支持跨数据源的字段过滤,即需要对每个数据源单独设置过滤条件,数据源 ID 不 - 允许使用通配符 \\**。 - - 暂不支持对字段使用函数计算,比如不支持 "YEAR(public.user.created_at) = 2023" - - 暂不支持多个过滤条件的组合,,比如不支持 "uid = {{user_id}} AND city_id = - {{city_id}}" - - 支持中文 Unicode 编码范围:4E00-9FFF(查询是否支持参考 - :https://www.unicode.org/cgi-bin/GetUnihanData.pl, 编码范围参考 - :https://www.unicode.org/charts/PDF/U4E00.pdf) - """ diff --git a/src/asktable/types/policy_list_params.py b/src/asktable/types/policy_list_params.py deleted file mode 100644 index 5a9e7ea6..00000000 --- a/src/asktable/types/policy_list_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from typing_extensions import TypedDict - -__all__ = ["PolicyListParams"] - - -class PolicyListParams(TypedDict, total=False): - name: Optional[str] - """策略名称""" - - page: int - """Page number""" - - policy_ids: Optional[List[str]] - """策略 ID 列表""" - - size: int - """Page size""" diff --git a/src/asktable/types/policy_update_params.py b/src/asktable/types/policy_update_params.py deleted file mode 100644 index dc1675b2..00000000 --- a/src/asktable/types/policy_update_params.py +++ /dev/null @@ -1,113 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["PolicyUpdateParams", "DatasetConfig", "DatasetConfigRegexPatterns", "DatasetConfigRowsFilter"] - - -class PolicyUpdateParams(TypedDict, total=False): - dataset_config: Optional[DatasetConfig] - """数据集配置""" - - name: Optional[str] - """名称""" - - permission: Optional[Literal["allow", "deny"]] - """权限""" - - -class DatasetConfigRegexPatterns(TypedDict, total=False): - fields_regex_pattern: Optional[str] - """Field 正则表达式,空值默认全选""" - - schemas_regex_pattern: Optional[str] - """Schema 正则表达式,空值默认全选""" - - tables_regex_pattern: Optional[str] - """Table 正则表达式,空值默认全选""" - - -class DatasetConfigRowsFilter(TypedDict, total=False): - condition: Required[str] - """Filter condition string""" - - db_regex: Required[str] - """Database regex pattern""" - - field_regex: Required[str] - """Field regex pattern""" - - operator_expression: Required[str] - """Operator expression""" - - table_regex: Required[str] - """Table regex pattern""" - - variables: List[str] - """Jinja2 variables in the condition""" - - -class DatasetConfig(TypedDict, total=False): - datasource_ids: Required[List[str]] - """ - 数据源 ID 列表,必填。 - 描述:用于指定策略适用的数据源。可以使用通配符 _ 表示所 - 有数据源。 - 示例:["ds_id_1","ds_id_2"],["_"]。 - """ - - regex_patterns: Optional[DatasetConfigRegexPatterns] - """ - 正则表达式。 - 描述:用于匹配指定数据源中 Schema(DB)、Table 和 Field 名称的三 - 个正则表达式,即同时满足这三个正则表达式的 DB、Table 和 Field 才被允许访问。 - - 注意:此字段为可选项。如果未提供,则默认包含指定数据源的所有数据。 - """ - - rows_filters: Optional[Dict[str, Iterable[DatasetConfigRowsFilter]]] - """行级别过滤器。 - - - 描述:指定行级别的过滤器,满足条件的行才可访问。 用户在查询数据的时候会自动对 - 结果集进行过滤,也同时会影响聚合计算(比如求 COUNT、SUM)的结果。 - - 格式: - - 按数据源组织,每个数据源对应一个过滤条件列表 `filter_condition` - - 每个 `filter_condition` 是一个字符串,格式为 - `".. "`。 - - 其中 `schema_name`、`table_name`、`field_name` 支持模糊匹配,比如支持 - `"*.*.*uid* = {{ user_id }}"`,来匹配所有包含 `uid` 的字段,且字段值等于 - `user_id` 的行。 - - 如何编写 `expression`: - - `expression` 中的操作符: - - 支持常见操作符:=, >, <, >=, <=, <>, !=, IN, NOT IN, LIKE, NOT LIKE, IS - NULL, IS NOT NULL - - `expression` 中的变量: - - 变量使用两个大括号括起来(支持 - [Jinja2](https://docs.jinkan.org/docs/jinja2/) 模版),比如 - {{user_id}},{{city_id}},{{merchant_id}} - - 变量的值需要在扮演角色时传递,全部使用字符串类型,比如 - "123","beijing","456" - - `expression` 中的函数: - - 支持内置函数 NOW() 获取当前时间,比如 "public.user.created_at > NOW() - 1 - YEAR" - - 数值、字符串、时间等字段的 `expression` 写法: - - 对于数值型、字符串类型的字段,可以直接填上常量或变量,都不用加引号,比如 - "public.user.age > {{age}}" ,"public.user.name = 张三 "或 - "public.user.name = {{name}} " - - 对于日期时间型字段 - - 使用单引号括起来的日期时间字符串进行过滤,比如 "public.user.created_at > - '2023-01-01 00:00:00 +00:00'" - - 使用变量时,需要使用大括号括起来,比如 "public.user.created_at > - {{start_date}}" - - 使用内置函数 NOW() 获取当前时间,比如 "public.user.created_at > NOW() - - 1 YEAR" - - 限制: - - 只允许当 permission = allow 时才可以设置该选项 - - 暂不支持跨数据源的字段过滤,即需要对每个数据源单独设置过滤条件,数据源 ID 不 - 允许使用通配符 \\**。 - - 暂不支持对字段使用函数计算,比如不支持 "YEAR(public.user.created_at) = 2023" - - 暂不支持多个过滤条件的组合,,比如不支持 "uid = {{user_id}} AND city_id = - {{city_id}}" - - 支持中文 Unicode 编码范围:4E00-9FFF(查询是否支持参考 - :https://www.unicode.org/cgi-bin/GetUnihanData.pl, 编码范围参考 - :https://www.unicode.org/charts/PDF/U4E00.pdf) - """ diff --git a/src/asktable/types/preference_create_params.py b/src/asktable/types/preference_create_params.py deleted file mode 100644 index 884b1196..00000000 --- a/src/asktable/types/preference_create_params.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -__all__ = ["PreferenceCreateParams"] - - -class PreferenceCreateParams(TypedDict, total=False): - general_preference: Required[str] - """通用偏好设置内容""" - - sql_preference: Optional[str] - """SQL 偏好设置内容""" diff --git a/src/asktable/types/preference_create_response.py b/src/asktable/types/preference_create_response.py deleted file mode 100644 index 9016f33f..00000000 --- a/src/asktable/types/preference_create_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["PreferenceCreateResponse"] - - -class PreferenceCreateResponse(BaseModel): - id: str - """偏好设置 ID""" - - general_preference: str - """通用偏好设置内容""" - - project_id: str - """项目 ID""" - - sql_preference: Optional[str] = None - """SQL 偏好设置内容""" diff --git a/src/asktable/types/preference_retrieve_response.py b/src/asktable/types/preference_retrieve_response.py deleted file mode 100644 index 36afa791..00000000 --- a/src/asktable/types/preference_retrieve_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["PreferenceRetrieveResponse"] - - -class PreferenceRetrieveResponse(BaseModel): - id: str - """偏好设置 ID""" - - general_preference: str - """通用偏好设置内容""" - - project_id: str - """项目 ID""" - - sql_preference: Optional[str] = None - """SQL 偏好设置内容""" diff --git a/src/asktable/types/preference_update_params.py b/src/asktable/types/preference_update_params.py deleted file mode 100644 index bb83fbe8..00000000 --- a/src/asktable/types/preference_update_params.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -__all__ = ["PreferenceUpdateParams"] - - -class PreferenceUpdateParams(TypedDict, total=False): - general_preference: Optional[str] - """通用偏好设置内容""" - - sql_preference: Optional[str] - """SQL 偏好设置内容""" diff --git a/src/asktable/types/preference_update_response.py b/src/asktable/types/preference_update_response.py deleted file mode 100644 index a317deae..00000000 --- a/src/asktable/types/preference_update_response.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["PreferenceUpdateResponse"] - - -class PreferenceUpdateResponse(BaseModel): - id: str - """偏好设置 ID""" - - general_preference: str - """通用偏好设置内容""" - - project_id: str - """项目 ID""" - - sql_preference: Optional[str] = None - """SQL 偏好设置内容""" diff --git a/src/asktable/types/project_list_model_groups_response.py b/src/asktable/types/project_list_model_groups_response.py index 21df8bd4..e177012e 100644 --- a/src/asktable/types/project_list_model_groups_response.py +++ b/src/asktable/types/project_list_model_groups_response.py @@ -1,10 +1,30 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional from typing_extensions import TypeAlias -from .sys.model_group import ModelGroup +from .._models import BaseModel -__all__ = ["ProjectListModelGroupsResponse"] +__all__ = ["ProjectListModelGroupsResponse", "ProjectListModelGroupsResponseItem"] -ProjectListModelGroupsResponse: TypeAlias = List[ModelGroup] + +class ProjectListModelGroupsResponseItem(BaseModel): + """ + 项目级用户视角,仅暴露选择器需要的字段。 + 敏感配置(api_key/base_url/extra_headers/model_configs)由系统级端点处理。 + """ + + id: str + """模型组 ID""" + + name: str + """模型组名称(绑定 project.llm_model_group)""" + + display_name: Optional[str] = None + """展示名称""" + + is_default: Optional[bool] = None + """是否为系统默认组""" + + +ProjectListModelGroupsResponse: TypeAlias = List[ProjectListModelGroupsResponseItem] diff --git a/src/asktable/types/query_response.py b/src/asktable/types/query_response.py deleted file mode 100644 index f57289fb..00000000 --- a/src/asktable/types/query_response.py +++ /dev/null @@ -1,69 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["QueryResponse", "Query", "Request", "Timing"] - - -class Query(BaseModel): - sql: str - """SQL 语句""" - - parameterized_sql: Optional[str] = None - """参数化后的 SQL 语句""" - - params: Optional[object] = None - """参数""" - - -class Request(BaseModel): - datasource_id: str - """数据源 ID""" - - question: str - """查询语句""" - - parameterize: Optional[bool] = None - """是否将参数分开传递""" - - role_id: Optional[str] = None - """ - 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - """ - - role_variables: Optional[object] = None - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" - - -class Timing(BaseModel): - llm_duration: Optional[float] = None - - total_duration: Optional[float] = None - - -class QueryResponse(BaseModel): - id: str - - created_at: datetime - - duration: int - - modified_at: datetime - - project_id: str - - query: Optional[Query] = None - - request: Request - - status: str - - err_msg: Optional[str] = None - - timing: Optional[Timing] = None - - trace_id: Optional[str] = None diff --git a/src/asktable/types/role.py b/src/asktable/types/role.py deleted file mode 100644 index 5683f5c5..00000000 --- a/src/asktable/types/role.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["Role"] - - -class Role(BaseModel): - id: str - - created_at: datetime - - description: Optional[str] = None - - modified_at: datetime - - name: str - - project_id: str - - policy_ids: Optional[List[str]] = None - """策略列表。注意:如果为空或者不传则不绑定策略""" diff --git a/src/asktable/types/role_create_params.py b/src/asktable/types/role_create_params.py deleted file mode 100644 index 4750a3e0..00000000 --- a/src/asktable/types/role_create_params.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from typing_extensions import Required, TypedDict - -__all__ = ["RoleCreateParams"] - - -class RoleCreateParams(TypedDict, total=False): - name: Required[str] - """名称""" - - policy_ids: Optional[List[str]] - """策略列表。注意:如果为空或者不传则不绑定策略""" diff --git a/src/asktable/types/role_get_polices_response.py b/src/asktable/types/role_get_polices_response.py deleted file mode 100644 index 85b32bb2..00000000 --- a/src/asktable/types/role_get_polices_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import TypeAlias - -from .shared.policy import Policy - -__all__ = ["RoleGetPolicesResponse"] - -RoleGetPolicesResponse: TypeAlias = List[Policy] diff --git a/src/asktable/types/role_get_variables_params.py b/src/asktable/types/role_get_variables_params.py deleted file mode 100644 index cebb567c..00000000 --- a/src/asktable/types/role_get_variables_params.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from typing_extensions import TypedDict - -__all__ = ["RoleGetVariablesParams"] - - -class RoleGetVariablesParams(TypedDict, total=False): - bot_id: Optional[str] - """Bot ID""" - - datasource_ids: Optional[List[str]] - """数据源 ID 列表""" diff --git a/src/asktable/types/role_list_params.py b/src/asktable/types/role_list_params.py deleted file mode 100644 index 851c0904..00000000 --- a/src/asktable/types/role_list_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from typing_extensions import TypedDict - -__all__ = ["RoleListParams"] - - -class RoleListParams(TypedDict, total=False): - name: Optional[str] - """角色名称""" - - page: int - """Page number""" - - role_ids: Optional[List[str]] - """角色 ID 列表""" - - size: int - """Page size""" diff --git a/src/asktable/types/role_update_params.py b/src/asktable/types/role_update_params.py deleted file mode 100644 index 6cb3bb99..00000000 --- a/src/asktable/types/role_update_params.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Optional -from typing_extensions import TypedDict - -__all__ = ["RoleUpdateParams"] - - -class RoleUpdateParams(TypedDict, total=False): - name: Optional[str] - """名称""" - - policy_ids: Optional[List[str]] - """策略列表。注意:如果为空或者不传则不绑定策略""" diff --git a/src/asktable/types/score_create_params.py b/src/asktable/types/score_create_params.py index dd034761..2a8be447 100644 --- a/src/asktable/types/score_create_params.py +++ b/src/asktable/types/score_create_params.py @@ -9,10 +9,7 @@ class ScoreCreateParams(TypedDict, total=False): chat_id: Required[str] - """聊天 ID""" message_id: Required[str] - """消息 ID""" score: Required[bool] - """评分""" diff --git a/src/asktable/types/secure_tunnel.py b/src/asktable/types/secure_tunnel.py deleted file mode 100644 index c6223b4e..00000000 --- a/src/asktable/types/secure_tunnel.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["SecureTunnel"] - - -class SecureTunnel(BaseModel): - id: str - - created_at: datetime - - modified_at: datetime - - name: str - """SecureTunnel 名称,不超过 20 个字符""" - - project_id: str - - status: str - - atst_server_host: Optional[str] = None - - atst_server_port: Optional[int] = None - - info: Optional[object] = None - - links_count: Optional[int] = None - - unique_key: Optional[str] = None diff --git a/src/asktable/types/securetunnel_create_params.py b/src/asktable/types/securetunnel_create_params.py deleted file mode 100644 index 53addf73..00000000 --- a/src/asktable/types/securetunnel_create_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["SecuretunnelCreateParams"] - - -class SecuretunnelCreateParams(TypedDict, total=False): - name: Required[str] - """SecureTunnel 名称,不超过 20 个字符""" diff --git a/src/asktable/types/securetunnel_list_links_params.py b/src/asktable/types/securetunnel_list_links_params.py deleted file mode 100644 index 3ff4ce62..00000000 --- a/src/asktable/types/securetunnel_list_links_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["SecuretunnelListLinksParams"] - - -class SecuretunnelListLinksParams(TypedDict, total=False): - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/securetunnel_list_links_response.py b/src/asktable/types/securetunnel_list_links_response.py deleted file mode 100644 index 15b8b118..00000000 --- a/src/asktable/types/securetunnel_list_links_response.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["SecuretunnelListLinksResponse"] - - -class SecuretunnelListLinksResponse(BaseModel): - id: str - - atst_id: str - - created_at: datetime - - datasource_ids: List[str] - - modified_at: datetime - - proxy_port: int - - status: str - - target_host: str - - target_port: int diff --git a/src/asktable/types/securetunnel_list_params.py b/src/asktable/types/securetunnel_list_params.py deleted file mode 100644 index f17189a5..00000000 --- a/src/asktable/types/securetunnel_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["SecuretunnelListParams"] - - -class SecuretunnelListParams(TypedDict, total=False): - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/securetunnel_update_params.py b/src/asktable/types/securetunnel_update_params.py deleted file mode 100644 index 6322936a..00000000 --- a/src/asktable/types/securetunnel_update_params.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -__all__ = ["SecuretunnelUpdateParams"] - - -class SecuretunnelUpdateParams(TypedDict, total=False): - client_info: Optional[object] - """客户端信息""" - - name: Optional[str] - """SecureTunnel 名称,不超过 20 个字符""" - - unique_key: Optional[str] - """唯一标识,用于更新客户端信息(容器 ID)""" diff --git a/src/asktable/types/shared/policy.py b/src/asktable/types/shared/policy.py index 0fd1b6db..b411a06f 100644 --- a/src/asktable/types/shared/policy.py +++ b/src/asktable/types/shared/policy.py @@ -1,41 +1,72 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Optional +from typing import List, Optional from datetime import datetime from typing_extensions import Literal from ..._models import BaseModel -__all__ = ["Policy", "DatasetConfig", "DatasetConfigRegexPatterns"] +__all__ = ["Policy", "Fields", "FieldsPattern", "RowFilter", "Schemas", "SchemasPattern", "Tables", "TablesPattern"] -class DatasetConfigRegexPatterns(BaseModel): - fields_regex_pattern: Optional[str] = None - """Field 正则表达式,空值默认全选""" +class FieldsPattern(BaseModel): + type: Literal["exact", "prefix", "suffix", "include"] - schemas_regex_pattern: Optional[str] = None - """Schema 正则表达式,空值默认全选""" + value: str - tables_regex_pattern: Optional[str] = None - """Table 正则表达式,空值默认全选""" +class Fields(BaseModel): + """Field 匹配规则""" -class DatasetConfig(BaseModel): - datasource_ids: List[str] - """ - 数据源 ID 列表,必填。 - 描述:用于指定策略适用的数据源。可以使用通配符 _ 表示所 - 有数据源。 - 示例:["ds_id_1","ds_id_2"],["_"]。 - """ + combinator: Optional[Literal["and", "or"]] = None - regex_patterns: Optional[DatasetConfigRegexPatterns] = None - """ - 正则表达式。 - 描述:用于匹配指定数据源中 Schema(DB)、Table 和 Field 名称的三 - 个正则表达式,即同时满足这三个正则表达式的 DB、Table 和 Field 才被允许访问。 - - 注意:此字段为可选项。如果未提供,则默认包含指定数据源的所有数据。 - """ + patterns: Optional[List[FieldsPattern]] = None - rows_filters: Optional[Dict[str, List[str]]] = None - """行过滤器""" + +class RowFilter(BaseModel): + """单条行过滤器。schema_name / table_name / field_name 允许 "*" 通配。""" + + datasource_id: str + + field_name: str + + operator: Literal[ + "=", "!=", "<>", ">", "<", ">=", "<=", "IN", "NOT IN", "LIKE", "NOT LIKE", "IS NULL", "IS NOT NULL" + ] + + schema_name: str + + table_name: str + + value: Optional[str] = None + + +class SchemasPattern(BaseModel): + type: Literal["exact", "prefix", "suffix", "include"] + + value: str + + +class Schemas(BaseModel): + """Schema 匹配规则;空 patterns = 不过滤""" + + combinator: Optional[Literal["and", "or"]] = None + + patterns: Optional[List[SchemasPattern]] = None + + +class TablesPattern(BaseModel): + type: Literal["exact", "prefix", "suffix", "include"] + + value: str + + +class Tables(BaseModel): + """Table 匹配规则""" + + combinator: Optional[Literal["and", "or"]] = None + + patterns: Optional[List[TablesPattern]] = None class Policy(BaseModel): @@ -43,15 +74,30 @@ class Policy(BaseModel): created_at: datetime - dataset_config: DatasetConfig - - description: Optional[str] = None - modified_at: datetime name: str + """名称""" permission: Literal["allow", "deny"] """权限""" project_id: str + + datasource_ids: Optional[List[str]] = None + """数据源 ID 列表;允许为空(新建空白态)""" + + description: Optional[str] = None + """描述""" + + fields: Optional[Fields] = None + """Field 匹配规则""" + + row_filters: Optional[List[RowFilter]] = None + """行过滤器(顶层扁平 list,每项带 datasource_id)""" + + schemas: Optional[Schemas] = None + """Schema 匹配规则;空 patterns = 不过滤""" + + tables: Optional[Tables] = None + """Table 匹配规则""" diff --git a/src/asktable/types/sql_create_params.py b/src/asktable/types/sql_create_params.py deleted file mode 100644 index 515dbd47..00000000 --- a/src/asktable/types/sql_create_params.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -__all__ = ["SqlCreateParams"] - - -class SqlCreateParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" - - question: Required[str] - """查询语句""" - - parameterize: bool - """是否将参数分开传递""" - - role_id: Optional[str] - """ - 角色 ID,将扮演这个角色来执行对话,用于权限控制。若无,则跳过鉴权,即可查询所有 - 数据 - """ - - role_variables: Optional[object] - """在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递""" diff --git a/src/asktable/types/sql_list_params.py b/src/asktable/types/sql_list_params.py deleted file mode 100644 index e0d36142..00000000 --- a/src/asktable/types/sql_list_params.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -__all__ = ["SqlListParams"] - - -class SqlListParams(TypedDict, total=False): - datasource_id: Optional[str] - """数据源 ID""" - - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/sy_update_config_params.py b/src/asktable/types/sy_update_config_params.py deleted file mode 100644 index fd7c7246..00000000 --- a/src/asktable/types/sy_update_config_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -__all__ = ["SyUpdateConfigParams"] - - -class SyUpdateConfigParams(TypedDict, total=False): - global_table_limit: Optional[int] - """表限制数量""" diff --git a/src/asktable/types/sy_update_config_response.py b/src/asktable/types/sy_update_config_response.py deleted file mode 100644 index 9d77316d..00000000 --- a/src/asktable/types/sy_update_config_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["SyUpdateConfigResponse"] - - -class SyUpdateConfigResponse(BaseModel): - global_table_limit: Optional[int] = None - """表限制数量""" diff --git a/src/asktable/types/sys/__init__.py b/src/asktable/types/sys/__init__.py index 603cf14d..088f68ea 100644 --- a/src/asktable/types/sys/__init__.py +++ b/src/asktable/types/sys/__init__.py @@ -4,9 +4,10 @@ from .api_key import APIKey as APIKey from .project import Project as Project -from .model_group import ModelGroup as ModelGroup from .project_list_params import ProjectListParams as ProjectListParams from .project_create_params import ProjectCreateParams as ProjectCreateParams from .project_import_params import ProjectImportParams as ProjectImportParams from .project_update_params import ProjectUpdateParams as ProjectUpdateParams +from .project_export_response import ProjectExportResponse as ProjectExportResponse +from .project_import_response import ProjectImportResponse as ProjectImportResponse from .project_model_groups_response import ProjectModelGroupsResponse as ProjectModelGroupsResponse diff --git a/src/asktable/types/sys/api_key.py b/src/asktable/types/sys/api_key.py index 1827ee5f..2aa5bb16 100644 --- a/src/asktable/types/sys/api_key.py +++ b/src/asktable/types/sys/api_key.py @@ -13,7 +13,7 @@ class APIKey(BaseModel): id: str """API Key ID""" - ak_role: Literal["sys", "admin", "asker", "visitor"] + ak_role: Literal["sys", "admin", "asker"] """API key 的角色""" created_at: datetime diff --git a/src/asktable/types/sys/model_group.py b/src/asktable/types/sys/model_group.py deleted file mode 100644 index d37d6270..00000000 --- a/src/asktable/types/sys/model_group.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["ModelGroup"] - - -class ModelGroup(BaseModel): - id: str - """模型组 ID""" - - agent: str - """Agent 模型""" - - fast: str - """快速模型""" - - image: str - """图片模型""" - - name: str - """模型组名称""" - - omni: str - """通用模型""" - - sql: str - """SQL 模型""" diff --git a/src/asktable/types/sys/project.py b/src/asktable/types/sys/project.py index c1e4abe4..95a3151c 100644 --- a/src/asktable/types/sys/project.py +++ b/src/asktable/types/sys/project.py @@ -1,5 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional from datetime import datetime from ..._models import BaseModel @@ -14,9 +15,6 @@ class Project(BaseModel): created_at: datetime """创建时间""" - llm_model_group: str - """模型组""" - locked: int """是否锁定""" @@ -25,3 +23,6 @@ class Project(BaseModel): name: str """项目名称""" + + llm_model_group: Optional[str] = None + """模型组,None 表示跟随系统默认""" diff --git a/src/asktable/types/score_create_response.py b/src/asktable/types/sys/project_export_response.py similarity index 53% rename from src/asktable/types/score_create_response.py rename to src/asktable/types/sys/project_export_response.py index b773e0e1..30135eed 100644 --- a/src/asktable/types/score_create_response.py +++ b/src/asktable/types/sys/project_export_response.py @@ -1,7 +1,8 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Dict from typing_extensions import TypeAlias -__all__ = ["ScoreCreateResponse"] +__all__ = ["ProjectExportResponse"] -ScoreCreateResponse: TypeAlias = bool +ProjectExportResponse: TypeAlias = Dict[str, object] diff --git a/src/asktable/types/sys/project_import_params.py b/src/asktable/types/sys/project_import_params.py index d244232a..52b5fdb6 100644 --- a/src/asktable/types/sys/project_import_params.py +++ b/src/asktable/types/sys/project_import_params.py @@ -2,10 +2,11 @@ from __future__ import annotations +from typing import Dict from typing_extensions import Required, TypedDict __all__ = ["ProjectImportParams"] class ProjectImportParams(TypedDict, total=False): - body: Required[object] + body: Required[Dict[str, object]] diff --git a/src/asktable/types/sys/project_import_response.py b/src/asktable/types/sys/project_import_response.py new file mode 100644 index 00000000..e98dcd60 --- /dev/null +++ b/src/asktable/types/sys/project_import_response.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["ProjectImportResponse"] + +ProjectImportResponse: TypeAlias = Dict[str, object] diff --git a/src/asktable/types/sys/project_list_params.py b/src/asktable/types/sys/project_list_params.py index f0b103dc..661b42ad 100644 --- a/src/asktable/types/sys/project_list_params.py +++ b/src/asktable/types/sys/project_list_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import List, Optional +from typing import Optional from typing_extensions import TypedDict +from ..._types import SequenceNotStr + __all__ = ["ProjectListParams"] @@ -12,7 +14,7 @@ class ProjectListParams(TypedDict, total=False): page: int """Page number""" - project_ids: Optional[List[str]] + project_ids: Optional[SequenceNotStr[str]] """项目 ID 列表""" size: int diff --git a/src/asktable/types/sys/project_model_groups_response.py b/src/asktable/types/sys/project_model_groups_response.py index 5a4939f3..7e83dea7 100644 --- a/src/asktable/types/sys/project_model_groups_response.py +++ b/src/asktable/types/sys/project_model_groups_response.py @@ -1,10 +1,88 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List -from typing_extensions import TypeAlias +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias -from .model_group import ModelGroup +from pydantic import Field as FieldInfo -__all__ = ["ProjectModelGroupsResponse"] +from ..._models import BaseModel -ProjectModelGroupsResponse: TypeAlias = List[ModelGroup] +__all__ = [ + "ProjectModelGroupsResponse", + "ProjectModelGroupsResponseItem", + "ProjectModelGroupsResponseItemModels", + "ProjectModelGroupsResponseItemModelConfigs", +] + + +class ProjectModelGroupsResponseItemModels(BaseModel): + """角色→模型映射""" + + agent: Optional[str] = None + + fast: Optional[str] = None + + omni: Optional[str] = None + + +class ProjectModelGroupsResponseItemModelConfigs(BaseModel): + """Per-model 配置,key 为 model ID""" + + capabilities: Optional[Dict[str, object]] = None + + context_window: Optional[int] = None + + display_name: Optional[str] = None + + enabled: Optional[bool] = None + + passthrough_reasoning: Optional[bool] = None + + provider_options: Optional[Dict[str, object]] = None + + +class ProjectModelGroupsResponseItem(BaseModel): + id: str + """模型组 ID""" + + api_key: str + """API 密钥""" + + available_models: List[str] + """可用模型列表""" + + base_url: str + """OpenAI 兼容 API 端点""" + + created_at: datetime + """创建时间""" + + extra_headers: Dict[str, str] + """额外请求头""" + + models: ProjectModelGroupsResponseItemModels + """角色 → 模型映射""" + + modified_at: datetime + """修改时间""" + + name: str + """模型组名称""" + + api_format: Optional[Literal["openai_chat", "anthropic"]] = None + """API 协议格式""" + + display_name: Optional[str] = None + """展示名称""" + + is_default: Optional[bool] = None + """是否为默认组""" + + api_model_configs: Optional[Dict[str, ProjectModelGroupsResponseItemModelConfigs]] = FieldInfo( + alias="model_configs", default=None + ) + """Per-model 配置""" + + +ProjectModelGroupsResponse: TypeAlias = List[ProjectModelGroupsResponseItem] diff --git a/src/asktable/types/sys/project_update_params.py b/src/asktable/types/sys/project_update_params.py index 312fe6f8..c8bde44f 100644 --- a/src/asktable/types/sys/project_update_params.py +++ b/src/asktable/types/sys/project_update_params.py @@ -9,6 +9,9 @@ class ProjectUpdateParams(TypedDict, total=False): + is_public: Optional[bool] + """是否公开项目""" + llm_model_group: Optional[str] """模型组""" diff --git a/src/asktable/types/sys/projects/__init__.py b/src/asktable/types/sys/projects/__init__.py index 6fd494c1..baa4c7fc 100644 --- a/src/asktable/types/sys/projects/__init__.py +++ b/src/asktable/types/sys/projects/__init__.py @@ -6,3 +6,4 @@ from .api_key_list_response import APIKeyListResponse as APIKeyListResponse from .api_key_create_response import APIKeyCreateResponse as APIKeyCreateResponse from .api_key_create_token_params import APIKeyCreateTokenParams as APIKeyCreateTokenParams +from .api_key_create_token_response import APIKeyCreateTokenResponse as APIKeyCreateTokenResponse diff --git a/src/asktable/types/sys/projects/api_key_create_params.py b/src/asktable/types/sys/projects/api_key_create_params.py index cd42517a..f2629b95 100644 --- a/src/asktable/types/sys/projects/api_key_create_params.py +++ b/src/asktable/types/sys/projects/api_key_create_params.py @@ -8,5 +8,5 @@ class APIKeyCreateParams(TypedDict, total=False): - ak_role: Required[Literal["sys", "admin", "asker", "visitor"]] + ak_role: Required[Literal["sys", "admin", "asker"]] """API key 的角色""" diff --git a/src/asktable/types/sys/projects/api_key_create_response.py b/src/asktable/types/sys/projects/api_key_create_response.py index b468a0f8..71241946 100644 --- a/src/asktable/types/sys/projects/api_key_create_response.py +++ b/src/asktable/types/sys/projects/api_key_create_response.py @@ -13,7 +13,7 @@ class APIKeyCreateResponse(BaseModel): id: str """API Key ID""" - ak_role: Literal["sys", "admin", "asker", "visitor"] + ak_role: Literal["sys", "admin", "asker"] """API key 的角色""" created_at: datetime diff --git a/src/asktable/types/sys/projects/api_key_create_token_params.py b/src/asktable/types/sys/projects/api_key_create_token_params.py index 212976c8..48b671b5 100644 --- a/src/asktable/types/sys/projects/api_key_create_token_params.py +++ b/src/asktable/types/sys/projects/api_key_create_token_params.py @@ -2,14 +2,14 @@ from __future__ import annotations -from typing import Optional +from typing import Dict, Optional from typing_extensions import Literal, TypedDict __all__ = ["APIKeyCreateTokenParams", "ChatRole"] class APIKeyCreateTokenParams(TypedDict, total=False): - ak_role: Literal["sys", "admin", "asker", "visitor"] + ak_role: Literal["sys", "admin", "asker"] """The role for the API key""" chat_role: Optional[ChatRole] @@ -18,13 +18,15 @@ class APIKeyCreateTokenParams(TypedDict, total=False): token_ttl: int """The time-to-live for the token in seconds""" - user_profile: Optional[object] + user_profile: Optional[Dict[str, object]] """Optional user profile data""" class ChatRole(TypedDict, total=False): + """The chat role""" + role_id: Optional[str] """The chat role ID""" - role_variables: Optional[object] + role_variables: Optional[Dict[str, object]] """The chat role variables""" diff --git a/src/asktable/types/sys/projects/api_key_create_token_response.py b/src/asktable/types/sys/projects/api_key_create_token_response.py new file mode 100644 index 00000000..106eedb6 --- /dev/null +++ b/src/asktable/types/sys/projects/api_key_create_token_response.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["APIKeyCreateTokenResponse"] + +APIKeyCreateTokenResponse: TypeAlias = Dict[str, object] diff --git a/src/asktable/types/tool_message.py b/src/asktable/types/tool_message.py deleted file mode 100644 index bbbea211..00000000 --- a/src/asktable/types/tool_message.py +++ /dev/null @@ -1,37 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ToolMessage", "Content", "ContentAttachment"] - - -class ContentAttachment(BaseModel): - info: object - - type: str - """The type of the attachment""" - - -class Content(BaseModel): - text: str - - attachments: Optional[List[ContentAttachment]] = None - - -class ToolMessage(BaseModel): - content: Content - - tool_call_id: str - - id: Optional[str] = None - - created_at: Optional[datetime] = None - """创建时间""" - - name: Optional[str] = None - - role: Optional[Literal["tool"]] = None diff --git a/src/asktable/types/training_create_params.py b/src/asktable/types/training_create_params.py deleted file mode 100644 index f8dec4df..00000000 --- a/src/asktable/types/training_create_params.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable, Optional -from typing_extensions import Required, TypedDict - -__all__ = ["TrainingCreateParams", "Body"] - - -class TrainingCreateParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" - - body: Required[Iterable[Body]] - - -class Body(TypedDict, total=False): - question: Required[str] - """用户问题""" - - sql: Required[str] - """用户问题对应的 SQL""" - - active: bool - """是否启用""" - - chat_id: Optional[str] - """聊天 ID""" - - msg_id: Optional[str] - """消息 ID""" - - role_id: Optional[str] - """角色 ID""" diff --git a/src/asktable/types/training_create_response.py b/src/asktable/types/training_create_response.py deleted file mode 100644 index 278021f5..00000000 --- a/src/asktable/types/training_create_response.py +++ /dev/null @@ -1,50 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal, TypeAlias - -from .._models import BaseModel - -__all__ = ["TrainingCreateResponse", "TrainingCreateResponseItem"] - - -class TrainingCreateResponseItem(BaseModel): - id: str - """训练数据 ID""" - - created_at: datetime - """创建时间""" - - datasource_id: str - """数据源 ID""" - - modified_at: datetime - """更新时间""" - - project_id: str - """项目 ID""" - - question: str - """用户问题""" - - source: Literal["import", "auto"] - """训练数据来源""" - - sql: str - """用户问题对应的 SQL""" - - active: Optional[bool] = None - """是否启用""" - - chat_id: Optional[str] = None - """聊天 ID""" - - msg_id: Optional[str] = None - """消息 ID""" - - role_id: Optional[str] = None - """角色 ID""" - - -TrainingCreateResponse: TypeAlias = List[TrainingCreateResponseItem] diff --git a/src/asktable/types/training_delete_params.py b/src/asktable/types/training_delete_params.py deleted file mode 100644 index e7325e7f..00000000 --- a/src/asktable/types/training_delete_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["TrainingDeleteParams"] - - -class TrainingDeleteParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" diff --git a/src/asktable/types/training_list_params.py b/src/asktable/types/training_list_params.py deleted file mode 100644 index bdf03a57..00000000 --- a/src/asktable/types/training_list_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["TrainingListParams"] - - -class TrainingListParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" - - page: int - """Page number""" - - size: int - """Page size""" diff --git a/src/asktable/types/training_list_response.py b/src/asktable/types/training_list_response.py deleted file mode 100644 index bc22d53a..00000000 --- a/src/asktable/types/training_list_response.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["TrainingListResponse"] - - -class TrainingListResponse(BaseModel): - id: str - """训练数据 ID""" - - created_at: datetime - """创建时间""" - - datasource_id: str - """数据源 ID""" - - modified_at: datetime - """更新时间""" - - project_id: str - """项目 ID""" - - question: str - """用户问题""" - - source: Literal["import", "auto"] - """训练数据来源""" - - sql: str - """用户问题对应的 SQL""" - - active: Optional[bool] = None - """是否启用""" - - chat_id: Optional[str] = None - """聊天 ID""" - - msg_id: Optional[str] = None - """消息 ID""" - - role_id: Optional[str] = None - """角色 ID""" diff --git a/src/asktable/types/training_update_params.py b/src/asktable/types/training_update_params.py deleted file mode 100644 index 82d56a3f..00000000 --- a/src/asktable/types/training_update_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -__all__ = ["TrainingUpdateParams"] - - -class TrainingUpdateParams(TypedDict, total=False): - datasource_id: Required[str] - """数据源 ID""" - - active: Optional[bool] - """是否启用""" - - question: Optional[str] - """用户问题""" - - role_id: Optional[str] - """角色 ID""" - - sql: Optional[str] - """用户问题对应的 SQL""" diff --git a/src/asktable/types/training_update_response.py b/src/asktable/types/training_update_response.py deleted file mode 100644 index 3817394d..00000000 --- a/src/asktable/types/training_update_response.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["TrainingUpdateResponse"] - - -class TrainingUpdateResponse(BaseModel): - id: str - """训练数据 ID""" - - created_at: datetime - """创建时间""" - - datasource_id: str - """数据源 ID""" - - modified_at: datetime - """更新时间""" - - project_id: str - """项目 ID""" - - question: str - """用户问题""" - - source: Literal["import", "auto"] - """训练数据来源""" - - sql: str - """用户问题对应的 SQL""" - - active: Optional[bool] = None - """是否启用""" - - chat_id: Optional[str] = None - """聊天 ID""" - - msg_id: Optional[str] = None - """消息 ID""" - - role_id: Optional[str] = None - """角色 ID""" diff --git a/src/asktable/types/user/project_retrieve_model_groups_response.py b/src/asktable/types/user/project_retrieve_model_groups_response.py index d2f36279..d49855e7 100644 --- a/src/asktable/types/user/project_retrieve_model_groups_response.py +++ b/src/asktable/types/user/project_retrieve_model_groups_response.py @@ -1,10 +1,30 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional from typing_extensions import TypeAlias -from ..sys.model_group import ModelGroup +from ..._models import BaseModel -__all__ = ["ProjectRetrieveModelGroupsResponse"] +__all__ = ["ProjectRetrieveModelGroupsResponse", "ProjectRetrieveModelGroupsResponseItem"] -ProjectRetrieveModelGroupsResponse: TypeAlias = List[ModelGroup] + +class ProjectRetrieveModelGroupsResponseItem(BaseModel): + """ + 项目级用户视角,仅暴露选择器需要的字段。 + 敏感配置(api_key/base_url/extra_headers/model_configs)由系统级端点处理。 + """ + + id: str + """模型组 ID""" + + name: str + """模型组名称(绑定 project.llm_model_group)""" + + display_name: Optional[str] = None + """展示名称""" + + is_default: Optional[bool] = None + """是否为系统默认组""" + + +ProjectRetrieveModelGroupsResponse: TypeAlias = List[ProjectRetrieveModelGroupsResponseItem] diff --git a/src/asktable/types/user_message.py b/src/asktable/types/user_message.py deleted file mode 100644 index c7ea626b..00000000 --- a/src/asktable/types/user_message.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["UserMessage", "Content", "ContentAttachment"] - - -class ContentAttachment(BaseModel): - info: object - - type: str - """The type of the attachment""" - - -class Content(BaseModel): - text: str - - attachments: Optional[List[ContentAttachment]] = None - - -class UserMessage(BaseModel): - content: Content - - id: Optional[str] = None - - created_at: Optional[datetime] = None - """创建时间""" - - name: Optional[str] = None - - role: Optional[Literal["human"]] = None diff --git a/tests/api_resources/ats/__init__.py b/tests/api_resources/ats/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/ats/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/ats/test_task.py b/tests/api_resources/ats/test_task.py deleted file mode 100644 index 9479b977..00000000 --- a/tests/api_resources/ats/test_task.py +++ /dev/null @@ -1,428 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types.ats import ( - TaskRunResponse, - TaskListResponse, - TaskRetrieveResponse, - TaskGetCaseTasksResponse, -) -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestTask: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - task = client.ats.task.retrieve( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) - assert_matches_type(TaskRetrieveResponse, task, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.ats.task.with_raw_response.retrieve( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - task = response.parse() - assert_matches_type(TaskRetrieveResponse, task, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.ats.task.with_streaming_response.retrieve( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - task = response.parse() - assert_matches_type(TaskRetrieveResponse, task, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.task.with_raw_response.retrieve( - ats_task_id="ats_task_id", - ats_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_task_id` but received ''"): - client.ats.task.with_raw_response.retrieve( - ats_task_id="", - ats_id="ats_id", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - task = client.ats.task.list( - ats_id="ats_id", - ) - assert_matches_type(SyncPage[TaskListResponse], task, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - task = client.ats.task.list( - ats_id="ats_id", - page=1, - size=1, - ) - assert_matches_type(SyncPage[TaskListResponse], task, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.ats.task.with_raw_response.list( - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - task = response.parse() - assert_matches_type(SyncPage[TaskListResponse], task, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.ats.task.with_streaming_response.list( - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - task = response.parse() - assert_matches_type(SyncPage[TaskListResponse], task, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.task.with_raw_response.list( - ats_id="", - ) - - @parametrize - def test_method_get_case_tasks(self, client: Asktable) -> None: - task = client.ats.task.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) - assert_matches_type(TaskGetCaseTasksResponse, task, path=["response"]) - - @parametrize - def test_method_get_case_tasks_with_all_params(self, client: Asktable) -> None: - task = client.ats.task.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="ats_id", - page=1, - size=1, - ) - assert_matches_type(TaskGetCaseTasksResponse, task, path=["response"]) - - @parametrize - def test_raw_response_get_case_tasks(self, client: Asktable) -> None: - response = client.ats.task.with_raw_response.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - task = response.parse() - assert_matches_type(TaskGetCaseTasksResponse, task, path=["response"]) - - @parametrize - def test_streaming_response_get_case_tasks(self, client: Asktable) -> None: - with client.ats.task.with_streaming_response.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - task = response.parse() - assert_matches_type(TaskGetCaseTasksResponse, task, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_case_tasks(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.task.with_raw_response.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_task_id` but received ''"): - client.ats.task.with_raw_response.get_case_tasks( - ats_task_id="", - ats_id="ats_id", - ) - - @parametrize - def test_method_run(self, client: Asktable) -> None: - task = client.ats.task.run( - ats_id="ats_id", - datasource_id="datasource_id", - specific_case_ids=["string"], - ) - assert_matches_type(TaskRunResponse, task, path=["response"]) - - @parametrize - def test_raw_response_run(self, client: Asktable) -> None: - response = client.ats.task.with_raw_response.run( - ats_id="ats_id", - datasource_id="datasource_id", - specific_case_ids=["string"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - task = response.parse() - assert_matches_type(TaskRunResponse, task, path=["response"]) - - @parametrize - def test_streaming_response_run(self, client: Asktable) -> None: - with client.ats.task.with_streaming_response.run( - ats_id="ats_id", - datasource_id="datasource_id", - specific_case_ids=["string"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - task = response.parse() - assert_matches_type(TaskRunResponse, task, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_run(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.task.with_raw_response.run( - ats_id="", - datasource_id="datasource_id", - specific_case_ids=["string"], - ) - - -class TestAsyncTask: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - task = await async_client.ats.task.retrieve( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) - assert_matches_type(TaskRetrieveResponse, task, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.task.with_raw_response.retrieve( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - task = await response.parse() - assert_matches_type(TaskRetrieveResponse, task, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.task.with_streaming_response.retrieve( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - task = await response.parse() - assert_matches_type(TaskRetrieveResponse, task, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.task.with_raw_response.retrieve( - ats_task_id="ats_task_id", - ats_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_task_id` but received ''"): - await async_client.ats.task.with_raw_response.retrieve( - ats_task_id="", - ats_id="ats_id", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - task = await async_client.ats.task.list( - ats_id="ats_id", - ) - assert_matches_type(AsyncPage[TaskListResponse], task, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - task = await async_client.ats.task.list( - ats_id="ats_id", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[TaskListResponse], task, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.task.with_raw_response.list( - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - task = await response.parse() - assert_matches_type(AsyncPage[TaskListResponse], task, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.task.with_streaming_response.list( - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - task = await response.parse() - assert_matches_type(AsyncPage[TaskListResponse], task, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.task.with_raw_response.list( - ats_id="", - ) - - @parametrize - async def test_method_get_case_tasks(self, async_client: AsyncAsktable) -> None: - task = await async_client.ats.task.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) - assert_matches_type(TaskGetCaseTasksResponse, task, path=["response"]) - - @parametrize - async def test_method_get_case_tasks_with_all_params(self, async_client: AsyncAsktable) -> None: - task = await async_client.ats.task.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="ats_id", - page=1, - size=1, - ) - assert_matches_type(TaskGetCaseTasksResponse, task, path=["response"]) - - @parametrize - async def test_raw_response_get_case_tasks(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.task.with_raw_response.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - task = await response.parse() - assert_matches_type(TaskGetCaseTasksResponse, task, path=["response"]) - - @parametrize - async def test_streaming_response_get_case_tasks(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.task.with_streaming_response.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - task = await response.parse() - assert_matches_type(TaskGetCaseTasksResponse, task, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_case_tasks(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.task.with_raw_response.get_case_tasks( - ats_task_id="ats_task_id", - ats_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_task_id` but received ''"): - await async_client.ats.task.with_raw_response.get_case_tasks( - ats_task_id="", - ats_id="ats_id", - ) - - @parametrize - async def test_method_run(self, async_client: AsyncAsktable) -> None: - task = await async_client.ats.task.run( - ats_id="ats_id", - datasource_id="datasource_id", - specific_case_ids=["string"], - ) - assert_matches_type(TaskRunResponse, task, path=["response"]) - - @parametrize - async def test_raw_response_run(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.task.with_raw_response.run( - ats_id="ats_id", - datasource_id="datasource_id", - specific_case_ids=["string"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - task = await response.parse() - assert_matches_type(TaskRunResponse, task, path=["response"]) - - @parametrize - async def test_streaming_response_run(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.task.with_streaming_response.run( - ats_id="ats_id", - datasource_id="datasource_id", - specific_case_ids=["string"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - task = await response.parse() - assert_matches_type(TaskRunResponse, task, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_run(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.task.with_raw_response.run( - ats_id="", - datasource_id="datasource_id", - specific_case_ids=["string"], - ) diff --git a/tests/api_resources/ats/test_test_case.py b/tests/api_resources/ats/test_test_case.py deleted file mode 100644 index 7a9a1281..00000000 --- a/tests/api_resources/ats/test_test_case.py +++ /dev/null @@ -1,570 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types.ats import ( - TestCaseListResponse, - TestCaseCreateResponse, - TestCaseUpdateResponse, - TestCaseRetrieveResponse, -) -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestTestCase: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - test_case = client.ats.test_case.create( - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - assert_matches_type(TestCaseCreateResponse, test_case, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - test_case = client.ats.test_case.create( - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - role_id="role_id", - role_variables={}, - ) - assert_matches_type(TestCaseCreateResponse, test_case, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.ats.test_case.with_raw_response.create( - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = response.parse() - assert_matches_type(TestCaseCreateResponse, test_case, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.ats.test_case.with_streaming_response.create( - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = response.parse() - assert_matches_type(TestCaseCreateResponse, test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_create(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.test_case.with_raw_response.create( - ats_id="", - expected_sql="expected_sql", - question="question", - ) - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - test_case = client.ats.test_case.retrieve( - atc_id="atc_id", - ats_id="ats_id", - ) - assert_matches_type(TestCaseRetrieveResponse, test_case, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.ats.test_case.with_raw_response.retrieve( - atc_id="atc_id", - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = response.parse() - assert_matches_type(TestCaseRetrieveResponse, test_case, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.ats.test_case.with_streaming_response.retrieve( - atc_id="atc_id", - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = response.parse() - assert_matches_type(TestCaseRetrieveResponse, test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.test_case.with_raw_response.retrieve( - atc_id="atc_id", - ats_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `atc_id` but received ''"): - client.ats.test_case.with_raw_response.retrieve( - atc_id="", - ats_id="ats_id", - ) - - @parametrize - def test_method_update(self, client: Asktable) -> None: - test_case = client.ats.test_case.update( - atc_id="atc_id", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - assert_matches_type(TestCaseUpdateResponse, test_case, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - test_case = client.ats.test_case.update( - atc_id="atc_id", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - role_id="role_id", - role_variables={}, - ) - assert_matches_type(TestCaseUpdateResponse, test_case, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.ats.test_case.with_raw_response.update( - atc_id="atc_id", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = response.parse() - assert_matches_type(TestCaseUpdateResponse, test_case, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.ats.test_case.with_streaming_response.update( - atc_id="atc_id", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = response.parse() - assert_matches_type(TestCaseUpdateResponse, test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.test_case.with_raw_response.update( - atc_id="atc_id", - ats_id="", - expected_sql="expected_sql", - question="question", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `atc_id` but received ''"): - client.ats.test_case.with_raw_response.update( - atc_id="", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - test_case = client.ats.test_case.list( - ats_id="ats_id", - ) - assert_matches_type(SyncPage[TestCaseListResponse], test_case, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - test_case = client.ats.test_case.list( - ats_id="ats_id", - page=1, - size=1, - ) - assert_matches_type(SyncPage[TestCaseListResponse], test_case, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.ats.test_case.with_raw_response.list( - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = response.parse() - assert_matches_type(SyncPage[TestCaseListResponse], test_case, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.ats.test_case.with_streaming_response.list( - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = response.parse() - assert_matches_type(SyncPage[TestCaseListResponse], test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.test_case.with_raw_response.list( - ats_id="", - ) - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - test_case = client.ats.test_case.delete( - atc_id="atc_id", - ats_id="ats_id", - ) - assert_matches_type(object, test_case, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.ats.test_case.with_raw_response.delete( - atc_id="atc_id", - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = response.parse() - assert_matches_type(object, test_case, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.ats.test_case.with_streaming_response.delete( - atc_id="atc_id", - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = response.parse() - assert_matches_type(object, test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.test_case.with_raw_response.delete( - atc_id="atc_id", - ats_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `atc_id` but received ''"): - client.ats.test_case.with_raw_response.delete( - atc_id="", - ats_id="ats_id", - ) - - -class TestAsyncTestCase: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - test_case = await async_client.ats.test_case.create( - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - assert_matches_type(TestCaseCreateResponse, test_case, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - test_case = await async_client.ats.test_case.create( - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - role_id="role_id", - role_variables={}, - ) - assert_matches_type(TestCaseCreateResponse, test_case, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.test_case.with_raw_response.create( - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = await response.parse() - assert_matches_type(TestCaseCreateResponse, test_case, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.test_case.with_streaming_response.create( - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = await response.parse() - assert_matches_type(TestCaseCreateResponse, test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_create(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.test_case.with_raw_response.create( - ats_id="", - expected_sql="expected_sql", - question="question", - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - test_case = await async_client.ats.test_case.retrieve( - atc_id="atc_id", - ats_id="ats_id", - ) - assert_matches_type(TestCaseRetrieveResponse, test_case, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.test_case.with_raw_response.retrieve( - atc_id="atc_id", - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = await response.parse() - assert_matches_type(TestCaseRetrieveResponse, test_case, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.test_case.with_streaming_response.retrieve( - atc_id="atc_id", - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = await response.parse() - assert_matches_type(TestCaseRetrieveResponse, test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.test_case.with_raw_response.retrieve( - atc_id="atc_id", - ats_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `atc_id` but received ''"): - await async_client.ats.test_case.with_raw_response.retrieve( - atc_id="", - ats_id="ats_id", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - test_case = await async_client.ats.test_case.update( - atc_id="atc_id", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - assert_matches_type(TestCaseUpdateResponse, test_case, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - test_case = await async_client.ats.test_case.update( - atc_id="atc_id", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - role_id="role_id", - role_variables={}, - ) - assert_matches_type(TestCaseUpdateResponse, test_case, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.test_case.with_raw_response.update( - atc_id="atc_id", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = await response.parse() - assert_matches_type(TestCaseUpdateResponse, test_case, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.test_case.with_streaming_response.update( - atc_id="atc_id", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = await response.parse() - assert_matches_type(TestCaseUpdateResponse, test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.test_case.with_raw_response.update( - atc_id="atc_id", - ats_id="", - expected_sql="expected_sql", - question="question", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `atc_id` but received ''"): - await async_client.ats.test_case.with_raw_response.update( - atc_id="", - ats_id="ats_id", - expected_sql="expected_sql", - question="question", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - test_case = await async_client.ats.test_case.list( - ats_id="ats_id", - ) - assert_matches_type(AsyncPage[TestCaseListResponse], test_case, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - test_case = await async_client.ats.test_case.list( - ats_id="ats_id", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[TestCaseListResponse], test_case, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.test_case.with_raw_response.list( - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = await response.parse() - assert_matches_type(AsyncPage[TestCaseListResponse], test_case, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.test_case.with_streaming_response.list( - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = await response.parse() - assert_matches_type(AsyncPage[TestCaseListResponse], test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.test_case.with_raw_response.list( - ats_id="", - ) - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - test_case = await async_client.ats.test_case.delete( - atc_id="atc_id", - ats_id="ats_id", - ) - assert_matches_type(object, test_case, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.test_case.with_raw_response.delete( - atc_id="atc_id", - ats_id="ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - test_case = await response.parse() - assert_matches_type(object, test_case, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.test_case.with_streaming_response.delete( - atc_id="atc_id", - ats_id="ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - test_case = await response.parse() - assert_matches_type(object, test_case, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.test_case.with_raw_response.delete( - atc_id="atc_id", - ats_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `atc_id` but received ''"): - await async_client.ats.test_case.with_raw_response.delete( - atc_id="", - ats_id="ats_id", - ) diff --git a/tests/api_resources/chats/__init__.py b/tests/api_resources/chats/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/chats/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/chats/test_messages.py b/tests/api_resources/chats/test_messages.py deleted file mode 100644 index 93280c1b..00000000 --- a/tests/api_resources/chats/test_messages.py +++ /dev/null @@ -1,303 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.pagination import SyncPage, AsyncPage -from asktable.types.chats import ( - MessageListResponse, - MessageCreateResponse, - MessageRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestMessages: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - message = client.chats.messages.create( - chat_id="chat_id", - question="question", - ) - assert_matches_type(MessageCreateResponse, message, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.chats.messages.with_raw_response.create( - chat_id="chat_id", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(MessageCreateResponse, message, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.chats.messages.with_streaming_response.create( - chat_id="chat_id", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = response.parse() - assert_matches_type(MessageCreateResponse, message, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_create(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - client.chats.messages.with_raw_response.create( - chat_id="", - question="question", - ) - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - message = client.chats.messages.retrieve( - message_id="message_id", - chat_id="chat_id", - ) - assert_matches_type(MessageRetrieveResponse, message, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.chats.messages.with_raw_response.retrieve( - message_id="message_id", - chat_id="chat_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(MessageRetrieveResponse, message, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.chats.messages.with_streaming_response.retrieve( - message_id="message_id", - chat_id="chat_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = response.parse() - assert_matches_type(MessageRetrieveResponse, message, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - client.chats.messages.with_raw_response.retrieve( - message_id="message_id", - chat_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.chats.messages.with_raw_response.retrieve( - message_id="", - chat_id="chat_id", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - message = client.chats.messages.list( - chat_id="chat_id", - ) - assert_matches_type(SyncPage[MessageListResponse], message, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - message = client.chats.messages.list( - chat_id="chat_id", - page=1, - size=1, - ) - assert_matches_type(SyncPage[MessageListResponse], message, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.chats.messages.with_raw_response.list( - chat_id="chat_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(SyncPage[MessageListResponse], message, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.chats.messages.with_streaming_response.list( - chat_id="chat_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = response.parse() - assert_matches_type(SyncPage[MessageListResponse], message, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - client.chats.messages.with_raw_response.list( - chat_id="", - ) - - -class TestAsyncMessages: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - message = await async_client.chats.messages.create( - chat_id="chat_id", - question="question", - ) - assert_matches_type(MessageCreateResponse, message, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.chats.messages.with_raw_response.create( - chat_id="chat_id", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(MessageCreateResponse, message, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.chats.messages.with_streaming_response.create( - chat_id="chat_id", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = await response.parse() - assert_matches_type(MessageCreateResponse, message, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_create(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - await async_client.chats.messages.with_raw_response.create( - chat_id="", - question="question", - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - message = await async_client.chats.messages.retrieve( - message_id="message_id", - chat_id="chat_id", - ) - assert_matches_type(MessageRetrieveResponse, message, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.chats.messages.with_raw_response.retrieve( - message_id="message_id", - chat_id="chat_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(MessageRetrieveResponse, message, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.chats.messages.with_streaming_response.retrieve( - message_id="message_id", - chat_id="chat_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = await response.parse() - assert_matches_type(MessageRetrieveResponse, message, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - await async_client.chats.messages.with_raw_response.retrieve( - message_id="message_id", - chat_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - await async_client.chats.messages.with_raw_response.retrieve( - message_id="", - chat_id="chat_id", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - message = await async_client.chats.messages.list( - chat_id="chat_id", - ) - assert_matches_type(AsyncPage[MessageListResponse], message, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - message = await async_client.chats.messages.list( - chat_id="chat_id", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[MessageListResponse], message, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.chats.messages.with_raw_response.list( - chat_id="chat_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(AsyncPage[MessageListResponse], message, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.chats.messages.with_streaming_response.list( - chat_id="chat_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = await response.parse() - assert_matches_type(AsyncPage[MessageListResponse], message, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - await async_client.chats.messages.with_raw_response.list( - chat_id="", - ) diff --git a/tests/api_resources/datasources/test_meta.py b/tests/api_resources/datasources/test_meta.py index ae7a8f6e..2dc54671 100644 --- a/tests/api_resources/datasources/test_meta.py +++ b/tests/api_resources/datasources/test_meta.py @@ -35,7 +35,7 @@ def test_method_create_with_all_params(self, client: Asktable) -> None: "foo": { "name": "name", "origin_desc": "origin_desc", - "custom_configs": {}, + "custom_configs": {"foo": "bar"}, "tables": { "foo": { "name": "name", @@ -146,7 +146,7 @@ def test_method_update_with_all_params(self, client: Asktable) -> None: "foo": { "name": "name", "origin_desc": "origin_desc", - "custom_configs": {}, + "custom_configs": {"foo": "bar"}, "tables": { "foo": { "name": "name", @@ -268,7 +268,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncAsktable) "foo": { "name": "name", "origin_desc": "origin_desc", - "custom_configs": {}, + "custom_configs": {"foo": "bar"}, "tables": { "foo": { "name": "name", @@ -379,7 +379,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncAsktable) "foo": { "name": "name", "origin_desc": "origin_desc", - "custom_configs": {}, + "custom_configs": {"foo": "bar"}, "tables": { "foo": { "name": "name", diff --git a/tests/api_resources/datasources/test_upload_params.py b/tests/api_resources/datasources/test_upload_params.py index cb22379f..6b3dad48 100644 --- a/tests/api_resources/datasources/test_upload_params.py +++ b/tests/api_resources/datasources/test_upload_params.py @@ -9,6 +9,7 @@ from asktable import Asktable, AsyncAsktable from tests.utils import assert_matches_type +from asktable.types.datasources import UploadParamCreateResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -19,7 +20,7 @@ class TestUploadParams: @parametrize def test_method_create(self, client: Asktable) -> None: upload_param = client.datasources.upload_params.create() - assert_matches_type(object, upload_param, path=["response"]) + assert_matches_type(UploadParamCreateResponse, upload_param, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Asktable) -> None: @@ -27,7 +28,7 @@ def test_method_create_with_all_params(self, client: Asktable) -> None: expiration=60, file_max_size=524288000, ) - assert_matches_type(object, upload_param, path=["response"]) + assert_matches_type(UploadParamCreateResponse, upload_param, path=["response"]) @parametrize def test_raw_response_create(self, client: Asktable) -> None: @@ -36,7 +37,7 @@ def test_raw_response_create(self, client: Asktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" upload_param = response.parse() - assert_matches_type(object, upload_param, path=["response"]) + assert_matches_type(UploadParamCreateResponse, upload_param, path=["response"]) @parametrize def test_streaming_response_create(self, client: Asktable) -> None: @@ -45,7 +46,7 @@ def test_streaming_response_create(self, client: Asktable) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" upload_param = response.parse() - assert_matches_type(object, upload_param, path=["response"]) + assert_matches_type(UploadParamCreateResponse, upload_param, path=["response"]) assert cast(Any, response.is_closed) is True @@ -58,7 +59,7 @@ class TestAsyncUploadParams: @parametrize async def test_method_create(self, async_client: AsyncAsktable) -> None: upload_param = await async_client.datasources.upload_params.create() - assert_matches_type(object, upload_param, path=["response"]) + assert_matches_type(UploadParamCreateResponse, upload_param, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: @@ -66,7 +67,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncAsktable) expiration=60, file_max_size=524288000, ) - assert_matches_type(object, upload_param, path=["response"]) + assert_matches_type(UploadParamCreateResponse, upload_param, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: @@ -75,7 +76,7 @@ async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" upload_param = await response.parse() - assert_matches_type(object, upload_param, path=["response"]) + assert_matches_type(UploadParamCreateResponse, upload_param, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: @@ -84,6 +85,6 @@ async def test_streaming_response_create(self, async_client: AsyncAsktable) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" upload_param = await response.parse() - assert_matches_type(object, upload_param, path=["response"]) + assert_matches_type(UploadParamCreateResponse, upload_param, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sys/projects/test_api_keys.py b/tests/api_resources/sys/projects/test_api_keys.py index 51966f80..79be98a6 100644 --- a/tests/api_resources/sys/projects/test_api_keys.py +++ b/tests/api_resources/sys/projects/test_api_keys.py @@ -12,6 +12,7 @@ from asktable.types.sys.projects import ( APIKeyListResponse, APIKeyCreateResponse, + APIKeyCreateTokenResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -153,7 +154,7 @@ def test_method_create_token(self, client: Asktable) -> None: api_key = client.sys.projects.api_keys.create_token( project_id="project_id", ) - assert_matches_type(object, api_key, path=["response"]) + assert_matches_type(APIKeyCreateTokenResponse, api_key, path=["response"]) @parametrize def test_method_create_token_with_all_params(self, client: Asktable) -> None: @@ -162,12 +163,12 @@ def test_method_create_token_with_all_params(self, client: Asktable) -> None: ak_role="asker", chat_role={ "role_id": "1", - "role_variables": {"id": "42"}, + "role_variables": {"id": "bar"}, }, token_ttl=900, - user_profile={"name": "张三"}, + user_profile={"name": "bar"}, ) - assert_matches_type(object, api_key, path=["response"]) + assert_matches_type(APIKeyCreateTokenResponse, api_key, path=["response"]) @parametrize def test_raw_response_create_token(self, client: Asktable) -> None: @@ -178,7 +179,7 @@ def test_raw_response_create_token(self, client: Asktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" api_key = response.parse() - assert_matches_type(object, api_key, path=["response"]) + assert_matches_type(APIKeyCreateTokenResponse, api_key, path=["response"]) @parametrize def test_streaming_response_create_token(self, client: Asktable) -> None: @@ -189,7 +190,7 @@ def test_streaming_response_create_token(self, client: Asktable) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" api_key = response.parse() - assert_matches_type(object, api_key, path=["response"]) + assert_matches_type(APIKeyCreateTokenResponse, api_key, path=["response"]) assert cast(Any, response.is_closed) is True @@ -339,7 +340,7 @@ async def test_method_create_token(self, async_client: AsyncAsktable) -> None: api_key = await async_client.sys.projects.api_keys.create_token( project_id="project_id", ) - assert_matches_type(object, api_key, path=["response"]) + assert_matches_type(APIKeyCreateTokenResponse, api_key, path=["response"]) @parametrize async def test_method_create_token_with_all_params(self, async_client: AsyncAsktable) -> None: @@ -348,12 +349,12 @@ async def test_method_create_token_with_all_params(self, async_client: AsyncAskt ak_role="asker", chat_role={ "role_id": "1", - "role_variables": {"id": "42"}, + "role_variables": {"id": "bar"}, }, token_ttl=900, - user_profile={"name": "张三"}, + user_profile={"name": "bar"}, ) - assert_matches_type(object, api_key, path=["response"]) + assert_matches_type(APIKeyCreateTokenResponse, api_key, path=["response"]) @parametrize async def test_raw_response_create_token(self, async_client: AsyncAsktable) -> None: @@ -364,7 +365,7 @@ async def test_raw_response_create_token(self, async_client: AsyncAsktable) -> N assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" api_key = await response.parse() - assert_matches_type(object, api_key, path=["response"]) + assert_matches_type(APIKeyCreateTokenResponse, api_key, path=["response"]) @parametrize async def test_streaming_response_create_token(self, async_client: AsyncAsktable) -> None: @@ -375,7 +376,7 @@ async def test_streaming_response_create_token(self, async_client: AsyncAsktable assert response.http_request.headers.get("X-Stainless-Lang") == "python" api_key = await response.parse() - assert_matches_type(object, api_key, path=["response"]) + assert_matches_type(APIKeyCreateTokenResponse, api_key, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/sys/test_projects.py b/tests/api_resources/sys/test_projects.py index 8b8d87c3..cbebf678 100644 --- a/tests/api_resources/sys/test_projects.py +++ b/tests/api_resources/sys/test_projects.py @@ -11,6 +11,8 @@ from tests.utils import assert_matches_type from asktable.types.sys import ( Project, + ProjectExportResponse, + ProjectImportResponse, ProjectModelGroupsResponse, ) from asktable.pagination import SyncPage, AsyncPage @@ -101,6 +103,7 @@ def test_method_update(self, client: Asktable) -> None: def test_method_update_with_all_params(self, client: Asktable) -> None: project = client.sys.projects.update( project_id="project_id", + is_public=True, llm_model_group="llm_model_group", locked=True, name="name", @@ -215,7 +218,7 @@ def test_method_export(self, client: Asktable) -> None: project = client.sys.projects.export( "project_id", ) - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectExportResponse, project, path=["response"]) @parametrize def test_raw_response_export(self, client: Asktable) -> None: @@ -226,7 +229,7 @@ def test_raw_response_export(self, client: Asktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" project = response.parse() - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectExportResponse, project, path=["response"]) @parametrize def test_streaming_response_export(self, client: Asktable) -> None: @@ -237,7 +240,7 @@ def test_streaming_response_export(self, client: Asktable) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" project = response.parse() - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectExportResponse, project, path=["response"]) assert cast(Any, response.is_closed) is True @@ -251,31 +254,31 @@ def test_path_params_export(self, client: Asktable) -> None: @parametrize def test_method_import(self, client: Asktable) -> None: project = client.sys.projects.import_( - body={}, + body={"foo": "bar"}, ) - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectImportResponse, project, path=["response"]) @parametrize def test_raw_response_import(self, client: Asktable) -> None: response = client.sys.projects.with_raw_response.import_( - body={}, + body={"foo": "bar"}, ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" project = response.parse() - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectImportResponse, project, path=["response"]) @parametrize def test_streaming_response_import(self, client: Asktable) -> None: with client.sys.projects.with_streaming_response.import_( - body={}, + body={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" project = response.parse() - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectImportResponse, project, path=["response"]) assert cast(Any, response.is_closed) is True @@ -390,6 +393,7 @@ async def test_method_update(self, async_client: AsyncAsktable) -> None: async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: project = await async_client.sys.projects.update( project_id="project_id", + is_public=True, llm_model_group="llm_model_group", locked=True, name="name", @@ -504,7 +508,7 @@ async def test_method_export(self, async_client: AsyncAsktable) -> None: project = await async_client.sys.projects.export( "project_id", ) - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectExportResponse, project, path=["response"]) @parametrize async def test_raw_response_export(self, async_client: AsyncAsktable) -> None: @@ -515,7 +519,7 @@ async def test_raw_response_export(self, async_client: AsyncAsktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" project = await response.parse() - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectExportResponse, project, path=["response"]) @parametrize async def test_streaming_response_export(self, async_client: AsyncAsktable) -> None: @@ -526,7 +530,7 @@ async def test_streaming_response_export(self, async_client: AsyncAsktable) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" project = await response.parse() - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectExportResponse, project, path=["response"]) assert cast(Any, response.is_closed) is True @@ -540,31 +544,31 @@ async def test_path_params_export(self, async_client: AsyncAsktable) -> None: @parametrize async def test_method_import(self, async_client: AsyncAsktable) -> None: project = await async_client.sys.projects.import_( - body={}, + body={"foo": "bar"}, ) - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectImportResponse, project, path=["response"]) @parametrize async def test_raw_response_import(self, async_client: AsyncAsktable) -> None: response = await async_client.sys.projects.with_raw_response.import_( - body={}, + body={"foo": "bar"}, ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" project = await response.parse() - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectImportResponse, project, path=["response"]) @parametrize async def test_streaming_response_import(self, async_client: AsyncAsktable) -> None: async with async_client.sys.projects.with_streaming_response.import_( - body={}, + body={"foo": "bar"}, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" project = await response.parse() - assert_matches_type(object, project, path=["response"]) + assert_matches_type(ProjectImportResponse, project, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_answers.py b/tests/api_resources/test_answers.py deleted file mode 100644 index dc2260f5..00000000 --- a/tests/api_resources/test_answers.py +++ /dev/null @@ -1,185 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import AnswerResponse -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestAnswers: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - answer = client.answers.create( - datasource_id="datasource_id", - question="question", - ) - assert_matches_type(AnswerResponse, answer, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - answer = client.answers.create( - datasource_id="datasource_id", - question="question", - max_rows=0, - role_id="role_id", - role_variables={}, - with_json=True, - ) - assert_matches_type(AnswerResponse, answer, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.answers.with_raw_response.create( - datasource_id="datasource_id", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - answer = response.parse() - assert_matches_type(AnswerResponse, answer, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.answers.with_streaming_response.create( - datasource_id="datasource_id", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - answer = response.parse() - assert_matches_type(AnswerResponse, answer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Asktable) -> None: - answer = client.answers.list() - assert_matches_type(SyncPage[AnswerResponse], answer, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - answer = client.answers.list( - datasource_id="datasource_id", - page=1, - size=1, - ) - assert_matches_type(SyncPage[AnswerResponse], answer, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.answers.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - answer = response.parse() - assert_matches_type(SyncPage[AnswerResponse], answer, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.answers.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - answer = response.parse() - assert_matches_type(SyncPage[AnswerResponse], answer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncAnswers: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - answer = await async_client.answers.create( - datasource_id="datasource_id", - question="question", - ) - assert_matches_type(AnswerResponse, answer, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - answer = await async_client.answers.create( - datasource_id="datasource_id", - question="question", - max_rows=0, - role_id="role_id", - role_variables={}, - with_json=True, - ) - assert_matches_type(AnswerResponse, answer, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.answers.with_raw_response.create( - datasource_id="datasource_id", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - answer = await response.parse() - assert_matches_type(AnswerResponse, answer, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.answers.with_streaming_response.create( - datasource_id="datasource_id", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - answer = await response.parse() - assert_matches_type(AnswerResponse, answer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - answer = await async_client.answers.list() - assert_matches_type(AsyncPage[AnswerResponse], answer, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - answer = await async_client.answers.list( - datasource_id="datasource_id", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[AnswerResponse], answer, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.answers.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - answer = await response.parse() - assert_matches_type(AsyncPage[AnswerResponse], answer, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.answers.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - answer = await response.parse() - assert_matches_type(AsyncPage[AnswerResponse], answer, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_ats.py b/tests/api_resources/test_ats.py deleted file mode 100644 index 7dc37e89..00000000 --- a/tests/api_resources/test_ats.py +++ /dev/null @@ -1,422 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import ( - ATSListResponse, - ATSCreateResponse, - ATSUpdateResponse, - ATSRetrieveResponse, -) -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestATS: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - ats = client.ats.create( - datasource_id="datasource_id", - name="name", - ) - assert_matches_type(ATSCreateResponse, ats, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.ats.with_raw_response.create( - datasource_id="datasource_id", - name="name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = response.parse() - assert_matches_type(ATSCreateResponse, ats, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.ats.with_streaming_response.create( - datasource_id="datasource_id", - name="name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = response.parse() - assert_matches_type(ATSCreateResponse, ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - ats = client.ats.retrieve( - "ats_id", - ) - assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.ats.with_raw_response.retrieve( - "ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = response.parse() - assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.ats.with_streaming_response.retrieve( - "ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = response.parse() - assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_update(self, client: Asktable) -> None: - ats = client.ats.update( - ats_id="ats_id", - name="name", - ) - assert_matches_type(ATSUpdateResponse, ats, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.ats.with_raw_response.update( - ats_id="ats_id", - name="name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = response.parse() - assert_matches_type(ATSUpdateResponse, ats, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.ats.with_streaming_response.update( - ats_id="ats_id", - name="name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = response.parse() - assert_matches_type(ATSUpdateResponse, ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.with_raw_response.update( - ats_id="", - name="name", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - ats = client.ats.list( - datasource_id="datasource_id", - ) - assert_matches_type(SyncPage[ATSListResponse], ats, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - ats = client.ats.list( - datasource_id="datasource_id", - page=1, - size=1, - ) - assert_matches_type(SyncPage[ATSListResponse], ats, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.ats.with_raw_response.list( - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = response.parse() - assert_matches_type(SyncPage[ATSListResponse], ats, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.ats.with_streaming_response.list( - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = response.parse() - assert_matches_type(SyncPage[ATSListResponse], ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - ats = client.ats.delete( - ats_id="ats_id", - datasource_id="datasource_id", - ) - assert_matches_type(object, ats, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.ats.with_raw_response.delete( - ats_id="ats_id", - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = response.parse() - assert_matches_type(object, ats, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.ats.with_streaming_response.delete( - ats_id="ats_id", - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = response.parse() - assert_matches_type(object, ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - client.ats.with_raw_response.delete( - ats_id="", - datasource_id="datasource_id", - ) - - -class TestAsyncATS: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - ats = await async_client.ats.create( - datasource_id="datasource_id", - name="name", - ) - assert_matches_type(ATSCreateResponse, ats, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.with_raw_response.create( - datasource_id="datasource_id", - name="name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = await response.parse() - assert_matches_type(ATSCreateResponse, ats, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.with_streaming_response.create( - datasource_id="datasource_id", - name="name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = await response.parse() - assert_matches_type(ATSCreateResponse, ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - ats = await async_client.ats.retrieve( - "ats_id", - ) - assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.with_raw_response.retrieve( - "ats_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = await response.parse() - assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.with_streaming_response.retrieve( - "ats_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = await response.parse() - assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - ats = await async_client.ats.update( - ats_id="ats_id", - name="name", - ) - assert_matches_type(ATSUpdateResponse, ats, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.with_raw_response.update( - ats_id="ats_id", - name="name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = await response.parse() - assert_matches_type(ATSUpdateResponse, ats, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.with_streaming_response.update( - ats_id="ats_id", - name="name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = await response.parse() - assert_matches_type(ATSUpdateResponse, ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.with_raw_response.update( - ats_id="", - name="name", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - ats = await async_client.ats.list( - datasource_id="datasource_id", - ) - assert_matches_type(AsyncPage[ATSListResponse], ats, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - ats = await async_client.ats.list( - datasource_id="datasource_id", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[ATSListResponse], ats, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.with_raw_response.list( - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = await response.parse() - assert_matches_type(AsyncPage[ATSListResponse], ats, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.with_streaming_response.list( - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = await response.parse() - assert_matches_type(AsyncPage[ATSListResponse], ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - ats = await async_client.ats.delete( - ats_id="ats_id", - datasource_id="datasource_id", - ) - assert_matches_type(object, ats, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.ats.with_raw_response.delete( - ats_id="ats_id", - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - ats = await response.parse() - assert_matches_type(object, ats, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.ats.with_streaming_response.delete( - ats_id="ats_id", - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - ats = await response.parse() - assert_matches_type(object, ats, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `ats_id` but received ''"): - await async_client.ats.with_raw_response.delete( - ats_id="", - datasource_id="datasource_id", - ) diff --git a/tests/api_resources/test_auth.py b/tests/api_resources/test_auth.py index e08b155e..0b637b87 100644 --- a/tests/api_resources/test_auth.py +++ b/tests/api_resources/test_auth.py @@ -9,7 +9,7 @@ from asktable import Asktable, AsyncAsktable from tests.utils import assert_matches_type -from asktable.types import AuthMeResponse +from asktable.types import AuthMeResponse, AuthCreateTokenResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -20,7 +20,7 @@ class TestAuth: @parametrize def test_method_create_token(self, client: Asktable) -> None: auth = client.auth.create_token() - assert_matches_type(object, auth, path=["response"]) + assert_matches_type(AuthCreateTokenResponse, auth, path=["response"]) @parametrize def test_method_create_token_with_all_params(self, client: Asktable) -> None: @@ -28,12 +28,12 @@ def test_method_create_token_with_all_params(self, client: Asktable) -> None: ak_role="asker", chat_role={ "role_id": "1", - "role_variables": {"id": "42"}, + "role_variables": {"id": "bar"}, }, token_ttl=900, - user_profile={"name": "张三"}, + user_profile={"name": "bar"}, ) - assert_matches_type(object, auth, path=["response"]) + assert_matches_type(AuthCreateTokenResponse, auth, path=["response"]) @parametrize def test_raw_response_create_token(self, client: Asktable) -> None: @@ -42,7 +42,7 @@ def test_raw_response_create_token(self, client: Asktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" auth = response.parse() - assert_matches_type(object, auth, path=["response"]) + assert_matches_type(AuthCreateTokenResponse, auth, path=["response"]) @parametrize def test_streaming_response_create_token(self, client: Asktable) -> None: @@ -51,7 +51,7 @@ def test_streaming_response_create_token(self, client: Asktable) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" auth = response.parse() - assert_matches_type(object, auth, path=["response"]) + assert_matches_type(AuthCreateTokenResponse, auth, path=["response"]) assert cast(Any, response.is_closed) is True @@ -89,7 +89,7 @@ class TestAsyncAuth: @parametrize async def test_method_create_token(self, async_client: AsyncAsktable) -> None: auth = await async_client.auth.create_token() - assert_matches_type(object, auth, path=["response"]) + assert_matches_type(AuthCreateTokenResponse, auth, path=["response"]) @parametrize async def test_method_create_token_with_all_params(self, async_client: AsyncAsktable) -> None: @@ -97,12 +97,12 @@ async def test_method_create_token_with_all_params(self, async_client: AsyncAskt ak_role="asker", chat_role={ "role_id": "1", - "role_variables": {"id": "42"}, + "role_variables": {"id": "bar"}, }, token_ttl=900, - user_profile={"name": "张三"}, + user_profile={"name": "bar"}, ) - assert_matches_type(object, auth, path=["response"]) + assert_matches_type(AuthCreateTokenResponse, auth, path=["response"]) @parametrize async def test_raw_response_create_token(self, async_client: AsyncAsktable) -> None: @@ -111,7 +111,7 @@ async def test_raw_response_create_token(self, async_client: AsyncAsktable) -> N assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" auth = await response.parse() - assert_matches_type(object, auth, path=["response"]) + assert_matches_type(AuthCreateTokenResponse, auth, path=["response"]) @parametrize async def test_streaming_response_create_token(self, async_client: AsyncAsktable) -> None: @@ -120,7 +120,7 @@ async def test_streaming_response_create_token(self, async_client: AsyncAsktable assert response.http_request.headers.get("X-Stainless-Lang") == "python" auth = await response.parse() - assert_matches_type(object, auth, path=["response"]) + assert_matches_type(AuthCreateTokenResponse, auth, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_bots.py b/tests/api_resources/test_bots.py deleted file mode 100644 index 09b2a320..00000000 --- a/tests/api_resources/test_bots.py +++ /dev/null @@ -1,587 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import Chatbot -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestBots: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - bot = client.bots.create( - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - name="name", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - bot = client.bots.create( - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - name="name", - color_theme="default", - debug=True, - extapi_ids=["string"], - interaction_rules=[ - { - "enabled": True, - "message": "抱歉,您的消息包含不当内容", - "name": "blocked_words_rule", - "version": "1.0.0", - "words": ["敏感词1", "敏感词2"], - } - ], - magic_input="magic_input", - max_rows=50, - publish=True, - query_balance=100, - sample_questions=["你好!今天中午有什么适合我的午餐?"], - webhooks=["string"], - welcome_message="欢迎使用AskTable", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.bots.with_raw_response.create( - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - name="name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.bots.with_streaming_response.create( - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - name="name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - bot = client.bots.retrieve( - "bot_id", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.bots.with_raw_response.retrieve( - "bot_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.bots.with_streaming_response.retrieve( - "bot_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `bot_id` but received ''"): - client.bots.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_update(self, client: Asktable) -> None: - bot = client.bots.update( - bot_id="bot_id", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - bot = client.bots.update( - bot_id="bot_id", - avatar_url="avatar_url", - color_theme="default", - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - debug=True, - extapi_ids=["string"], - interaction_rules=[ - { - "enabled": True, - "message": "抱歉,您的消息包含不当内容", - "name": "blocked_words_rule", - "version": "1.0.0", - "words": ["敏感词1", "敏感词2"], - } - ], - magic_input="magic_input", - max_rows=50, - name="name", - publish=True, - query_balance=100, - sample_questions=["你好!今天中午有什么适合我的午餐?"], - webhooks=["string"], - welcome_message="欢迎使用AskTable", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.bots.with_raw_response.update( - bot_id="bot_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.bots.with_streaming_response.update( - bot_id="bot_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `bot_id` but received ''"): - client.bots.with_raw_response.update( - bot_id="", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - bot = client.bots.list() - assert_matches_type(SyncPage[Chatbot], bot, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - bot = client.bots.list( - bot_ids=["string", "string"], - name="name", - page=1, - size=1, - ) - assert_matches_type(SyncPage[Chatbot], bot, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.bots.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = response.parse() - assert_matches_type(SyncPage[Chatbot], bot, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.bots.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = response.parse() - assert_matches_type(SyncPage[Chatbot], bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - bot = client.bots.delete( - "bot_id", - ) - assert_matches_type(object, bot, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.bots.with_raw_response.delete( - "bot_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = response.parse() - assert_matches_type(object, bot, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.bots.with_streaming_response.delete( - "bot_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = response.parse() - assert_matches_type(object, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `bot_id` but received ''"): - client.bots.with_raw_response.delete( - "", - ) - - @parametrize - def test_method_invite(self, client: Asktable) -> None: - bot = client.bots.invite( - bot_id="bot_id", - project_id="project_id", - ) - assert_matches_type(object, bot, path=["response"]) - - @parametrize - def test_raw_response_invite(self, client: Asktable) -> None: - response = client.bots.with_raw_response.invite( - bot_id="bot_id", - project_id="project_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = response.parse() - assert_matches_type(object, bot, path=["response"]) - - @parametrize - def test_streaming_response_invite(self, client: Asktable) -> None: - with client.bots.with_streaming_response.invite( - bot_id="bot_id", - project_id="project_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = response.parse() - assert_matches_type(object, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_invite(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `bot_id` but received ''"): - client.bots.with_raw_response.invite( - bot_id="", - project_id="project_id", - ) - - -class TestAsyncBots: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.create( - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - name="name", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.create( - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - name="name", - color_theme="default", - debug=True, - extapi_ids=["string"], - interaction_rules=[ - { - "enabled": True, - "message": "抱歉,您的消息包含不当内容", - "name": "blocked_words_rule", - "version": "1.0.0", - "words": ["敏感词1", "敏感词2"], - } - ], - magic_input="magic_input", - max_rows=50, - publish=True, - query_balance=100, - sample_questions=["你好!今天中午有什么适合我的午餐?"], - webhooks=["string"], - welcome_message="欢迎使用AskTable", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.bots.with_raw_response.create( - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - name="name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = await response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.bots.with_streaming_response.create( - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - name="name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = await response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.retrieve( - "bot_id", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.bots.with_raw_response.retrieve( - "bot_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = await response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.bots.with_streaming_response.retrieve( - "bot_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = await response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `bot_id` but received ''"): - await async_client.bots.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.update( - bot_id="bot_id", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.update( - bot_id="bot_id", - avatar_url="avatar_url", - color_theme="default", - datasource_ids=["ds_sJAbnNOUzu3R4DdCCOwe"], - debug=True, - extapi_ids=["string"], - interaction_rules=[ - { - "enabled": True, - "message": "抱歉,您的消息包含不当内容", - "name": "blocked_words_rule", - "version": "1.0.0", - "words": ["敏感词1", "敏感词2"], - } - ], - magic_input="magic_input", - max_rows=50, - name="name", - publish=True, - query_balance=100, - sample_questions=["你好!今天中午有什么适合我的午餐?"], - webhooks=["string"], - welcome_message="欢迎使用AskTable", - ) - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.bots.with_raw_response.update( - bot_id="bot_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = await response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.bots.with_streaming_response.update( - bot_id="bot_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = await response.parse() - assert_matches_type(Chatbot, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `bot_id` but received ''"): - await async_client.bots.with_raw_response.update( - bot_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.list() - assert_matches_type(AsyncPage[Chatbot], bot, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.list( - bot_ids=["string", "string"], - name="name", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[Chatbot], bot, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.bots.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = await response.parse() - assert_matches_type(AsyncPage[Chatbot], bot, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.bots.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = await response.parse() - assert_matches_type(AsyncPage[Chatbot], bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.delete( - "bot_id", - ) - assert_matches_type(object, bot, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.bots.with_raw_response.delete( - "bot_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = await response.parse() - assert_matches_type(object, bot, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.bots.with_streaming_response.delete( - "bot_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = await response.parse() - assert_matches_type(object, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `bot_id` but received ''"): - await async_client.bots.with_raw_response.delete( - "", - ) - - @parametrize - async def test_method_invite(self, async_client: AsyncAsktable) -> None: - bot = await async_client.bots.invite( - bot_id="bot_id", - project_id="project_id", - ) - assert_matches_type(object, bot, path=["response"]) - - @parametrize - async def test_raw_response_invite(self, async_client: AsyncAsktable) -> None: - response = await async_client.bots.with_raw_response.invite( - bot_id="bot_id", - project_id="project_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - bot = await response.parse() - assert_matches_type(object, bot, path=["response"]) - - @parametrize - async def test_streaming_response_invite(self, async_client: AsyncAsktable) -> None: - async with async_client.bots.with_streaming_response.invite( - bot_id="bot_id", - project_id="project_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - bot = await response.parse() - assert_matches_type(object, bot, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_invite(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `bot_id` but received ''"): - await async_client.bots.with_raw_response.invite( - bot_id="", - project_id="project_id", - ) diff --git a/tests/api_resources/test_business_glossary.py b/tests/api_resources/test_business_glossary.py deleted file mode 100644 index 5016bd69..00000000 --- a/tests/api_resources/test_business_glossary.py +++ /dev/null @@ -1,441 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import ( - Entry, - EntryWithDefinition, - BusinessGlossaryCreateResponse, -) -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestBusinessGlossary: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - business_glossary = client.business_glossary.create( - body=[ - { - "definition": "definition", - "term": "term", - } - ], - ) - assert_matches_type(BusinessGlossaryCreateResponse, business_glossary, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.business_glossary.with_raw_response.create( - body=[ - { - "definition": "definition", - "term": "term", - } - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = response.parse() - assert_matches_type(BusinessGlossaryCreateResponse, business_glossary, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.business_glossary.with_streaming_response.create( - body=[ - { - "definition": "definition", - "term": "term", - } - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = response.parse() - assert_matches_type(BusinessGlossaryCreateResponse, business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - business_glossary = client.business_glossary.retrieve( - "entry_id", - ) - assert_matches_type(EntryWithDefinition, business_glossary, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.business_glossary.with_raw_response.retrieve( - "entry_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = response.parse() - assert_matches_type(EntryWithDefinition, business_glossary, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.business_glossary.with_streaming_response.retrieve( - "entry_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = response.parse() - assert_matches_type(EntryWithDefinition, business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `entry_id` but received ''"): - client.business_glossary.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_update(self, client: Asktable) -> None: - business_glossary = client.business_glossary.update( - entry_id="entry_id", - ) - assert_matches_type(Entry, business_glossary, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - business_glossary = client.business_glossary.update( - entry_id="entry_id", - active=True, - aliases=["string"], - definition="definition", - payload={}, - term="term", - ) - assert_matches_type(Entry, business_glossary, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.business_glossary.with_raw_response.update( - entry_id="entry_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = response.parse() - assert_matches_type(Entry, business_glossary, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.business_glossary.with_streaming_response.update( - entry_id="entry_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = response.parse() - assert_matches_type(Entry, business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `entry_id` but received ''"): - client.business_glossary.with_raw_response.update( - entry_id="", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - business_glossary = client.business_glossary.list() - assert_matches_type(SyncPage[EntryWithDefinition], business_glossary, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - business_glossary = client.business_glossary.list( - page=1, - size=1, - term="term", - ) - assert_matches_type(SyncPage[EntryWithDefinition], business_glossary, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.business_glossary.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = response.parse() - assert_matches_type(SyncPage[EntryWithDefinition], business_glossary, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.business_glossary.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = response.parse() - assert_matches_type(SyncPage[EntryWithDefinition], business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - business_glossary = client.business_glossary.delete( - "entry_id", - ) - assert_matches_type(object, business_glossary, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.business_glossary.with_raw_response.delete( - "entry_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = response.parse() - assert_matches_type(object, business_glossary, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.business_glossary.with_streaming_response.delete( - "entry_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = response.parse() - assert_matches_type(object, business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `entry_id` but received ''"): - client.business_glossary.with_raw_response.delete( - "", - ) - - -class TestAsyncBusinessGlossary: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - business_glossary = await async_client.business_glossary.create( - body=[ - { - "definition": "definition", - "term": "term", - } - ], - ) - assert_matches_type(BusinessGlossaryCreateResponse, business_glossary, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.business_glossary.with_raw_response.create( - body=[ - { - "definition": "definition", - "term": "term", - } - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = await response.parse() - assert_matches_type(BusinessGlossaryCreateResponse, business_glossary, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.business_glossary.with_streaming_response.create( - body=[ - { - "definition": "definition", - "term": "term", - } - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = await response.parse() - assert_matches_type(BusinessGlossaryCreateResponse, business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - business_glossary = await async_client.business_glossary.retrieve( - "entry_id", - ) - assert_matches_type(EntryWithDefinition, business_glossary, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.business_glossary.with_raw_response.retrieve( - "entry_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = await response.parse() - assert_matches_type(EntryWithDefinition, business_glossary, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.business_glossary.with_streaming_response.retrieve( - "entry_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = await response.parse() - assert_matches_type(EntryWithDefinition, business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `entry_id` but received ''"): - await async_client.business_glossary.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - business_glossary = await async_client.business_glossary.update( - entry_id="entry_id", - ) - assert_matches_type(Entry, business_glossary, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - business_glossary = await async_client.business_glossary.update( - entry_id="entry_id", - active=True, - aliases=["string"], - definition="definition", - payload={}, - term="term", - ) - assert_matches_type(Entry, business_glossary, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.business_glossary.with_raw_response.update( - entry_id="entry_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = await response.parse() - assert_matches_type(Entry, business_glossary, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.business_glossary.with_streaming_response.update( - entry_id="entry_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = await response.parse() - assert_matches_type(Entry, business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `entry_id` but received ''"): - await async_client.business_glossary.with_raw_response.update( - entry_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - business_glossary = await async_client.business_glossary.list() - assert_matches_type(AsyncPage[EntryWithDefinition], business_glossary, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - business_glossary = await async_client.business_glossary.list( - page=1, - size=1, - term="term", - ) - assert_matches_type(AsyncPage[EntryWithDefinition], business_glossary, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.business_glossary.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = await response.parse() - assert_matches_type(AsyncPage[EntryWithDefinition], business_glossary, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.business_glossary.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = await response.parse() - assert_matches_type(AsyncPage[EntryWithDefinition], business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - business_glossary = await async_client.business_glossary.delete( - "entry_id", - ) - assert_matches_type(object, business_glossary, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.business_glossary.with_raw_response.delete( - "entry_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - business_glossary = await response.parse() - assert_matches_type(object, business_glossary, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.business_glossary.with_streaming_response.delete( - "entry_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - business_glossary = await response.parse() - assert_matches_type(object, business_glossary, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `entry_id` but received ''"): - await async_client.business_glossary.with_raw_response.delete( - "", - ) diff --git a/tests/api_resources/test_caches.py b/tests/api_resources/test_caches.py deleted file mode 100644 index 637c192e..00000000 --- a/tests/api_resources/test_caches.py +++ /dev/null @@ -1,98 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestCaches: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - cach = client.caches.delete( - "cache_id", - ) - assert cach is None - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.caches.with_raw_response.delete( - "cache_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - cach = response.parse() - assert cach is None - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.caches.with_streaming_response.delete( - "cache_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - cach = response.parse() - assert cach is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `cache_id` but received ''"): - client.caches.with_raw_response.delete( - "", - ) - - -class TestAsyncCaches: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - cach = await async_client.caches.delete( - "cache_id", - ) - assert cach is None - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.caches.with_raw_response.delete( - "cache_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - cach = await response.parse() - assert cach is None - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.caches.with_streaming_response.delete( - "cache_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - cach = await response.parse() - assert cach is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `cache_id` but received ''"): - await async_client.caches.with_raw_response.delete( - "", - ) diff --git a/tests/api_resources/test_chats.py b/tests/api_resources/test_chats.py deleted file mode 100644 index 9748cf24..00000000 --- a/tests/api_resources/test_chats.py +++ /dev/null @@ -1,323 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import Chat, ChatRetrieveResponse -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestChats: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - chat = client.chats.create() - assert_matches_type(Chat, chat, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - chat = client.chats.create( - bot_id="bot_42", - name="name", - role_id="role_42", - role_variables={"id": "123123123"}, - user_profile={ - "age": 18, - "is_male": True, - "name": "张三", - }, - ) - assert_matches_type(Chat, chat, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.chats.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = response.parse() - assert_matches_type(Chat, chat, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.chats.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = response.parse() - assert_matches_type(Chat, chat, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - chat = client.chats.retrieve( - "chat_id", - ) - assert_matches_type(ChatRetrieveResponse, chat, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.chats.with_raw_response.retrieve( - "chat_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = response.parse() - assert_matches_type(ChatRetrieveResponse, chat, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.chats.with_streaming_response.retrieve( - "chat_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = response.parse() - assert_matches_type(ChatRetrieveResponse, chat, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - client.chats.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - chat = client.chats.list() - assert_matches_type(SyncPage[Chat], chat, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - chat = client.chats.list( - page=1, - size=1, - ) - assert_matches_type(SyncPage[Chat], chat, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.chats.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = response.parse() - assert_matches_type(SyncPage[Chat], chat, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.chats.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = response.parse() - assert_matches_type(SyncPage[Chat], chat, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - chat = client.chats.delete( - "chat_id", - ) - assert chat is None - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.chats.with_raw_response.delete( - "chat_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = response.parse() - assert chat is None - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.chats.with_streaming_response.delete( - "chat_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = response.parse() - assert chat is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - client.chats.with_raw_response.delete( - "", - ) - - -class TestAsyncChats: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - chat = await async_client.chats.create() - assert_matches_type(Chat, chat, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - chat = await async_client.chats.create( - bot_id="bot_42", - name="name", - role_id="role_42", - role_variables={"id": "123123123"}, - user_profile={ - "age": 18, - "is_male": True, - "name": "张三", - }, - ) - assert_matches_type(Chat, chat, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.chats.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = await response.parse() - assert_matches_type(Chat, chat, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.chats.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = await response.parse() - assert_matches_type(Chat, chat, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - chat = await async_client.chats.retrieve( - "chat_id", - ) - assert_matches_type(ChatRetrieveResponse, chat, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.chats.with_raw_response.retrieve( - "chat_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = await response.parse() - assert_matches_type(ChatRetrieveResponse, chat, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.chats.with_streaming_response.retrieve( - "chat_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = await response.parse() - assert_matches_type(ChatRetrieveResponse, chat, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - await async_client.chats.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - chat = await async_client.chats.list() - assert_matches_type(AsyncPage[Chat], chat, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - chat = await async_client.chats.list( - page=1, - size=1, - ) - assert_matches_type(AsyncPage[Chat], chat, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.chats.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = await response.parse() - assert_matches_type(AsyncPage[Chat], chat, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.chats.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = await response.parse() - assert_matches_type(AsyncPage[Chat], chat, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - chat = await async_client.chats.delete( - "chat_id", - ) - assert chat is None - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.chats.with_raw_response.delete( - "chat_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - chat = await response.parse() - assert chat is None - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.chats.with_streaming_response.delete( - "chat_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - chat = await response.parse() - assert chat is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): - await async_client.chats.with_raw_response.delete( - "", - ) diff --git a/tests/api_resources/test_datasources.py b/tests/api_resources/test_datasources.py index ba4d2ab1..2ab4c033 100644 --- a/tests/api_resources/test_datasources.py +++ b/tests/api_resources/test_datasources.py @@ -37,7 +37,7 @@ def test_method_create_with_all_params(self, client: Asktable) -> None: "host": "192.168.0.10", "db": "at_test", "db_version": "5.7", - "extra_config": {"ssl_mode": "require"}, + "extra_config": {"ssl_mode": "bar"}, "password": "root", "port": 3306, "securetunnel_id": "atst_123456", @@ -123,7 +123,7 @@ def test_method_update_with_all_params(self, client: Asktable) -> None: access_config={ "db": "at_test", "db_version": "5.7", - "extra_config": {"ssl_mode": "require"}, + "extra_config": {"ssl_mode": "bar"}, "host": "192.168.0.10", "password": "root", "port": 3306, @@ -133,11 +133,12 @@ def test_method_update_with_all_params(self, client: Asktable) -> None: desc="数据源描述", engine="mysql", field_count=1, - meta_error="error message", - meta_status="success", + meta_status="available", name="用户库", - sample_questions="示例问题", + sample_questions=["示例问题1", "示例问题2"], schema_count=1, + sync_error={"message": "bar"}, + sync_status="success", table_count=1, ) assert_matches_type(Datasource, datasource, path=["response"]) @@ -249,7 +250,7 @@ def test_path_params_delete(self, client: Asktable) -> None: def test_method_add_file(self, client: Asktable) -> None: datasource = client.datasources.add_file( datasource_id="datasource_id", - file=b"raw file contents", + file="file", ) assert_matches_type(object, datasource, path=["response"]) @@ -257,7 +258,7 @@ def test_method_add_file(self, client: Asktable) -> None: def test_raw_response_add_file(self, client: Asktable) -> None: response = client.datasources.with_raw_response.add_file( datasource_id="datasource_id", - file=b"raw file contents", + file="file", ) assert response.is_closed is True @@ -269,7 +270,7 @@ def test_raw_response_add_file(self, client: Asktable) -> None: def test_streaming_response_add_file(self, client: Asktable) -> None: with client.datasources.with_streaming_response.add_file( datasource_id="datasource_id", - file=b"raw file contents", + file="file", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -284,7 +285,7 @@ def test_path_params_add_file(self, client: Asktable) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `datasource_id` but received ''"): client.datasources.with_raw_response.add_file( datasource_id="", - file=b"raw file contents", + file="file", ) @parametrize @@ -456,7 +457,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncAsktable) "host": "192.168.0.10", "db": "at_test", "db_version": "5.7", - "extra_config": {"ssl_mode": "require"}, + "extra_config": {"ssl_mode": "bar"}, "password": "root", "port": 3306, "securetunnel_id": "atst_123456", @@ -542,7 +543,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncAsktable) access_config={ "db": "at_test", "db_version": "5.7", - "extra_config": {"ssl_mode": "require"}, + "extra_config": {"ssl_mode": "bar"}, "host": "192.168.0.10", "password": "root", "port": 3306, @@ -552,11 +553,12 @@ async def test_method_update_with_all_params(self, async_client: AsyncAsktable) desc="数据源描述", engine="mysql", field_count=1, - meta_error="error message", - meta_status="success", + meta_status="available", name="用户库", - sample_questions="示例问题", + sample_questions=["示例问题1", "示例问题2"], schema_count=1, + sync_error={"message": "bar"}, + sync_status="success", table_count=1, ) assert_matches_type(Datasource, datasource, path=["response"]) @@ -668,7 +670,7 @@ async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: async def test_method_add_file(self, async_client: AsyncAsktable) -> None: datasource = await async_client.datasources.add_file( datasource_id="datasource_id", - file=b"raw file contents", + file="file", ) assert_matches_type(object, datasource, path=["response"]) @@ -676,7 +678,7 @@ async def test_method_add_file(self, async_client: AsyncAsktable) -> None: async def test_raw_response_add_file(self, async_client: AsyncAsktable) -> None: response = await async_client.datasources.with_raw_response.add_file( datasource_id="datasource_id", - file=b"raw file contents", + file="file", ) assert response.is_closed is True @@ -688,7 +690,7 @@ async def test_raw_response_add_file(self, async_client: AsyncAsktable) -> None: async def test_streaming_response_add_file(self, async_client: AsyncAsktable) -> None: async with async_client.datasources.with_streaming_response.add_file( datasource_id="datasource_id", - file=b"raw file contents", + file="file", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -703,7 +705,7 @@ async def test_path_params_add_file(self, async_client: AsyncAsktable) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `datasource_id` but received ''"): await async_client.datasources.with_raw_response.add_file( datasource_id="", - file=b"raw file contents", + file="file", ) @parametrize diff --git a/tests/api_resources/test_integration.py b/tests/api_resources/test_integration.py index 47336152..5de5b448 100644 --- a/tests/api_resources/test_integration.py +++ b/tests/api_resources/test_integration.py @@ -9,10 +9,6 @@ from asktable import Asktable, AsyncAsktable from tests.utils import assert_matches_type -from asktable.types import ( - Datasource, - FileAskResponse, -) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -20,52 +16,13 @@ class TestIntegration: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @parametrize - def test_method_create_excel_ds(self, client: Asktable) -> None: - integration = client.integration.create_excel_ds( - file_url="https://example.com", - ) - assert_matches_type(Datasource, integration, path=["response"]) - - @parametrize - def test_method_create_excel_ds_with_all_params(self, client: Asktable) -> None: - integration = client.integration.create_excel_ds( - file_url="https://example.com", - value_index=True, - ) - assert_matches_type(Datasource, integration, path=["response"]) - - @parametrize - def test_raw_response_create_excel_ds(self, client: Asktable) -> None: - response = client.integration.with_raw_response.create_excel_ds( - file_url="https://example.com", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - integration = response.parse() - assert_matches_type(Datasource, integration, path=["response"]) - - @parametrize - def test_streaming_response_create_excel_ds(self, client: Asktable) -> None: - with client.integration.with_streaming_response.create_excel_ds( - file_url="https://example.com", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - integration = response.parse() - assert_matches_type(Datasource, integration, path=["response"]) - - assert cast(Any, response.is_closed) is True - @parametrize def test_method_excel_csv_ask(self, client: Asktable) -> None: integration = client.integration.excel_csv_ask( file_url="https://example.com", question="question", ) - assert_matches_type(FileAskResponse, integration, path=["response"]) + assert_matches_type(object, integration, path=["response"]) @parametrize def test_method_excel_csv_ask_with_all_params(self, client: Asktable) -> None: @@ -74,7 +31,7 @@ def test_method_excel_csv_ask_with_all_params(self, client: Asktable) -> None: question="question", with_json=True, ) - assert_matches_type(FileAskResponse, integration, path=["response"]) + assert_matches_type(object, integration, path=["response"]) @parametrize def test_raw_response_excel_csv_ask(self, client: Asktable) -> None: @@ -86,7 +43,7 @@ def test_raw_response_excel_csv_ask(self, client: Asktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" integration = response.parse() - assert_matches_type(FileAskResponse, integration, path=["response"]) + assert_matches_type(object, integration, path=["response"]) @parametrize def test_streaming_response_excel_csv_ask(self, client: Asktable) -> None: @@ -98,7 +55,7 @@ def test_streaming_response_excel_csv_ask(self, client: Asktable) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" integration = response.parse() - assert_matches_type(FileAskResponse, integration, path=["response"]) + assert_matches_type(object, integration, path=["response"]) assert cast(Any, response.is_closed) is True @@ -108,52 +65,13 @@ class TestAsyncIntegration: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @parametrize - async def test_method_create_excel_ds(self, async_client: AsyncAsktable) -> None: - integration = await async_client.integration.create_excel_ds( - file_url="https://example.com", - ) - assert_matches_type(Datasource, integration, path=["response"]) - - @parametrize - async def test_method_create_excel_ds_with_all_params(self, async_client: AsyncAsktable) -> None: - integration = await async_client.integration.create_excel_ds( - file_url="https://example.com", - value_index=True, - ) - assert_matches_type(Datasource, integration, path=["response"]) - - @parametrize - async def test_raw_response_create_excel_ds(self, async_client: AsyncAsktable) -> None: - response = await async_client.integration.with_raw_response.create_excel_ds( - file_url="https://example.com", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - integration = await response.parse() - assert_matches_type(Datasource, integration, path=["response"]) - - @parametrize - async def test_streaming_response_create_excel_ds(self, async_client: AsyncAsktable) -> None: - async with async_client.integration.with_streaming_response.create_excel_ds( - file_url="https://example.com", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - integration = await response.parse() - assert_matches_type(Datasource, integration, path=["response"]) - - assert cast(Any, response.is_closed) is True - @parametrize async def test_method_excel_csv_ask(self, async_client: AsyncAsktable) -> None: integration = await async_client.integration.excel_csv_ask( file_url="https://example.com", question="question", ) - assert_matches_type(FileAskResponse, integration, path=["response"]) + assert_matches_type(object, integration, path=["response"]) @parametrize async def test_method_excel_csv_ask_with_all_params(self, async_client: AsyncAsktable) -> None: @@ -162,7 +80,7 @@ async def test_method_excel_csv_ask_with_all_params(self, async_client: AsyncAsk question="question", with_json=True, ) - assert_matches_type(FileAskResponse, integration, path=["response"]) + assert_matches_type(object, integration, path=["response"]) @parametrize async def test_raw_response_excel_csv_ask(self, async_client: AsyncAsktable) -> None: @@ -174,7 +92,7 @@ async def test_raw_response_excel_csv_ask(self, async_client: AsyncAsktable) -> assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" integration = await response.parse() - assert_matches_type(FileAskResponse, integration, path=["response"]) + assert_matches_type(object, integration, path=["response"]) @parametrize async def test_streaming_response_excel_csv_ask(self, async_client: AsyncAsktable) -> None: @@ -186,6 +104,6 @@ async def test_streaming_response_excel_csv_ask(self, async_client: AsyncAsktabl assert response.http_request.headers.get("X-Stainless-Lang") == "python" integration = await response.parse() - assert_matches_type(FileAskResponse, integration, path=["response"]) + assert_matches_type(object, integration, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_policies.py b/tests/api_resources/test_policies.py deleted file mode 100644 index b7c78fa4..00000000 --- a/tests/api_resources/test_policies.py +++ /dev/null @@ -1,573 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.pagination import SyncPage, AsyncPage -from asktable.types.shared import Policy - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPolicies: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - policy = client.policies.create( - dataset_config={"datasource_ids": ["string"]}, - name="policy_name", - permission="allow", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - policy = client.policies.create( - dataset_config={ - "datasource_ids": ["string"], - "regex_patterns": { - "fields_regex_pattern": ".*password.* | .*pwd.*", - "schemas_regex_pattern": "^public.*$", - "tables_regex_pattern": "^(user|shop).*$", - }, - "rows_filters": { - "ds_sJAbnNOUzu3R4DdCCOw2": ["public.shop.merchantId = {{merchant_id}}"], - "ds_sJAbnNOUzu3R4DdCCOwe": [ - "public.user.created_at > '2023-01-01 00:00:00 +00:00'", - "public.*.id = {{user_id}}", - "public.shop.city_id = {{city_id}}", - "*.shop.status = 'online'", - ], - }, - }, - name="policy_name", - permission="allow", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.policies.with_raw_response.create( - dataset_config={"datasource_ids": ["string"]}, - name="policy_name", - permission="allow", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.policies.with_streaming_response.create( - dataset_config={"datasource_ids": ["string"]}, - name="policy_name", - permission="allow", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - policy = client.policies.retrieve( - "policy_id", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.policies.with_raw_response.retrieve( - "policy_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.policies.with_streaming_response.retrieve( - "policy_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): - client.policies.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_update(self, client: Asktable) -> None: - policy = client.policies.update( - policy_id="policy_id", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - policy = client.policies.update( - policy_id="policy_id", - dataset_config={ - "datasource_ids": ["string"], - "regex_patterns": { - "fields_regex_pattern": ".*password.* | .*pwd.*", - "schemas_regex_pattern": "^public.*$", - "tables_regex_pattern": "^(user|shop).*$", - }, - "rows_filters": { - "ds_sJAbnNOUzu3R4DdCCOw2": [ - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - } - ], - "ds_sJAbnNOUzu3R4DdCCOwe": [ - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - }, - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - }, - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - }, - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - }, - ], - }, - }, - name="policy_name", - permission="allow", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.policies.with_raw_response.update( - policy_id="policy_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.policies.with_streaming_response.update( - policy_id="policy_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): - client.policies.with_raw_response.update( - policy_id="", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - policy = client.policies.list() - assert_matches_type(SyncPage[Policy], policy, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - policy = client.policies.list( - name="name", - page=1, - policy_ids=["string", "string"], - size=1, - ) - assert_matches_type(SyncPage[Policy], policy, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.policies.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = response.parse() - assert_matches_type(SyncPage[Policy], policy, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.policies.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = response.parse() - assert_matches_type(SyncPage[Policy], policy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - policy = client.policies.delete( - "policy_id", - ) - assert policy is None - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.policies.with_raw_response.delete( - "policy_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = response.parse() - assert policy is None - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.policies.with_streaming_response.delete( - "policy_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = response.parse() - assert policy is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): - client.policies.with_raw_response.delete( - "", - ) - - -class TestAsyncPolicies: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - policy = await async_client.policies.create( - dataset_config={"datasource_ids": ["string"]}, - name="policy_name", - permission="allow", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - policy = await async_client.policies.create( - dataset_config={ - "datasource_ids": ["string"], - "regex_patterns": { - "fields_regex_pattern": ".*password.* | .*pwd.*", - "schemas_regex_pattern": "^public.*$", - "tables_regex_pattern": "^(user|shop).*$", - }, - "rows_filters": { - "ds_sJAbnNOUzu3R4DdCCOw2": ["public.shop.merchantId = {{merchant_id}}"], - "ds_sJAbnNOUzu3R4DdCCOwe": [ - "public.user.created_at > '2023-01-01 00:00:00 +00:00'", - "public.*.id = {{user_id}}", - "public.shop.city_id = {{city_id}}", - "*.shop.status = 'online'", - ], - }, - }, - name="policy_name", - permission="allow", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.policies.with_raw_response.create( - dataset_config={"datasource_ids": ["string"]}, - name="policy_name", - permission="allow", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = await response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.policies.with_streaming_response.create( - dataset_config={"datasource_ids": ["string"]}, - name="policy_name", - permission="allow", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = await response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - policy = await async_client.policies.retrieve( - "policy_id", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.policies.with_raw_response.retrieve( - "policy_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = await response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.policies.with_streaming_response.retrieve( - "policy_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = await response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): - await async_client.policies.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - policy = await async_client.policies.update( - policy_id="policy_id", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - policy = await async_client.policies.update( - policy_id="policy_id", - dataset_config={ - "datasource_ids": ["string"], - "regex_patterns": { - "fields_regex_pattern": ".*password.* | .*pwd.*", - "schemas_regex_pattern": "^public.*$", - "tables_regex_pattern": "^(user|shop).*$", - }, - "rows_filters": { - "ds_sJAbnNOUzu3R4DdCCOw2": [ - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - } - ], - "ds_sJAbnNOUzu3R4DdCCOwe": [ - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - }, - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - }, - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - }, - { - "condition": "condition", - "db_regex": "db_regex", - "field_regex": "field_regex", - "operator_expression": "operator_expression", - "table_regex": "table_regex", - "variables": ["string"], - }, - ], - }, - }, - name="policy_name", - permission="allow", - ) - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.policies.with_raw_response.update( - policy_id="policy_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = await response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.policies.with_streaming_response.update( - policy_id="policy_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = await response.parse() - assert_matches_type(Policy, policy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): - await async_client.policies.with_raw_response.update( - policy_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - policy = await async_client.policies.list() - assert_matches_type(AsyncPage[Policy], policy, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - policy = await async_client.policies.list( - name="name", - page=1, - policy_ids=["string", "string"], - size=1, - ) - assert_matches_type(AsyncPage[Policy], policy, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.policies.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = await response.parse() - assert_matches_type(AsyncPage[Policy], policy, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.policies.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = await response.parse() - assert_matches_type(AsyncPage[Policy], policy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - policy = await async_client.policies.delete( - "policy_id", - ) - assert policy is None - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.policies.with_raw_response.delete( - "policy_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - policy = await response.parse() - assert policy is None - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.policies.with_streaming_response.delete( - "policy_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - policy = await response.parse() - assert policy is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): - await async_client.policies.with_raw_response.delete( - "", - ) diff --git a/tests/api_resources/test_preferences.py b/tests/api_resources/test_preferences.py deleted file mode 100644 index 06808683..00000000 --- a/tests/api_resources/test_preferences.py +++ /dev/null @@ -1,272 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import ( - PreferenceCreateResponse, - PreferenceUpdateResponse, - PreferenceRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPreferences: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - preference = client.preferences.create( - general_preference="general_preference", - ) - assert_matches_type(PreferenceCreateResponse, preference, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - preference = client.preferences.create( - general_preference="general_preference", - sql_preference="sql_preference", - ) - assert_matches_type(PreferenceCreateResponse, preference, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.preferences.with_raw_response.create( - general_preference="general_preference", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preference = response.parse() - assert_matches_type(PreferenceCreateResponse, preference, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.preferences.with_streaming_response.create( - general_preference="general_preference", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preference = response.parse() - assert_matches_type(PreferenceCreateResponse, preference, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - preference = client.preferences.retrieve() - assert_matches_type(PreferenceRetrieveResponse, preference, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.preferences.with_raw_response.retrieve() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preference = response.parse() - assert_matches_type(PreferenceRetrieveResponse, preference, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.preferences.with_streaming_response.retrieve() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preference = response.parse() - assert_matches_type(PreferenceRetrieveResponse, preference, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update(self, client: Asktable) -> None: - preference = client.preferences.update() - assert_matches_type(PreferenceUpdateResponse, preference, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - preference = client.preferences.update( - general_preference="general_preference", - sql_preference="sql_preference", - ) - assert_matches_type(PreferenceUpdateResponse, preference, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.preferences.with_raw_response.update() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preference = response.parse() - assert_matches_type(PreferenceUpdateResponse, preference, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.preferences.with_streaming_response.update() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preference = response.parse() - assert_matches_type(PreferenceUpdateResponse, preference, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - preference = client.preferences.delete() - assert_matches_type(object, preference, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.preferences.with_raw_response.delete() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preference = response.parse() - assert_matches_type(object, preference, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.preferences.with_streaming_response.delete() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preference = response.parse() - assert_matches_type(object, preference, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncPreferences: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - preference = await async_client.preferences.create( - general_preference="general_preference", - ) - assert_matches_type(PreferenceCreateResponse, preference, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - preference = await async_client.preferences.create( - general_preference="general_preference", - sql_preference="sql_preference", - ) - assert_matches_type(PreferenceCreateResponse, preference, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.preferences.with_raw_response.create( - general_preference="general_preference", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preference = await response.parse() - assert_matches_type(PreferenceCreateResponse, preference, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.preferences.with_streaming_response.create( - general_preference="general_preference", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preference = await response.parse() - assert_matches_type(PreferenceCreateResponse, preference, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - preference = await async_client.preferences.retrieve() - assert_matches_type(PreferenceRetrieveResponse, preference, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.preferences.with_raw_response.retrieve() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preference = await response.parse() - assert_matches_type(PreferenceRetrieveResponse, preference, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.preferences.with_streaming_response.retrieve() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preference = await response.parse() - assert_matches_type(PreferenceRetrieveResponse, preference, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - preference = await async_client.preferences.update() - assert_matches_type(PreferenceUpdateResponse, preference, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - preference = await async_client.preferences.update( - general_preference="general_preference", - sql_preference="sql_preference", - ) - assert_matches_type(PreferenceUpdateResponse, preference, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.preferences.with_raw_response.update() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preference = await response.parse() - assert_matches_type(PreferenceUpdateResponse, preference, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.preferences.with_streaming_response.update() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preference = await response.parse() - assert_matches_type(PreferenceUpdateResponse, preference, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - preference = await async_client.preferences.delete() - assert_matches_type(object, preference, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.preferences.with_raw_response.delete() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preference = await response.parse() - assert_matches_type(object, preference, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.preferences.with_streaming_response.delete() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preference = await response.parse() - assert_matches_type(object, preference, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_roles.py b/tests/api_resources/test_roles.py deleted file mode 100644 index b14375ad..00000000 --- a/tests/api_resources/test_roles.py +++ /dev/null @@ -1,592 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import ( - Role, - RoleGetPolicesResponse, -) -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestRoles: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - role = client.roles.create( - name="role_name", - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - role = client.roles.create( - name="role_name", - policy_ids=["policy_6uOnay1xDNsxLoHmCGf3", "policy_6uOnay1xDNsxLoHmCGf2"], - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.roles.with_raw_response.create( - name="role_name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = response.parse() - assert_matches_type(Role, role, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.roles.with_streaming_response.create( - name="role_name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = response.parse() - assert_matches_type(Role, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - role = client.roles.retrieve( - "role_id", - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.roles.with_raw_response.retrieve( - "role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = response.parse() - assert_matches_type(Role, role, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.roles.with_streaming_response.retrieve( - "role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = response.parse() - assert_matches_type(Role, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - client.roles.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_update(self, client: Asktable) -> None: - role = client.roles.update( - role_id="role_id", - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - role = client.roles.update( - role_id="role_id", - name="role_name", - policy_ids=["policy_6uOnay1xDNsxLoHmCGf3", "policy_6uOnay1xDNsxLoHmCGf2"], - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.roles.with_raw_response.update( - role_id="role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = response.parse() - assert_matches_type(Role, role, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.roles.with_streaming_response.update( - role_id="role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = response.parse() - assert_matches_type(Role, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - client.roles.with_raw_response.update( - role_id="", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - role = client.roles.list() - assert_matches_type(SyncPage[Role], role, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - role = client.roles.list( - name="name", - page=1, - role_ids=["string", "string"], - size=1, - ) - assert_matches_type(SyncPage[Role], role, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.roles.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = response.parse() - assert_matches_type(SyncPage[Role], role, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.roles.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = response.parse() - assert_matches_type(SyncPage[Role], role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - role = client.roles.delete( - "role_id", - ) - assert_matches_type(object, role, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.roles.with_raw_response.delete( - "role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = response.parse() - assert_matches_type(object, role, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.roles.with_streaming_response.delete( - "role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = response.parse() - assert_matches_type(object, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - client.roles.with_raw_response.delete( - "", - ) - - @parametrize - def test_method_get_polices(self, client: Asktable) -> None: - role = client.roles.get_polices( - "role_id", - ) - assert_matches_type(RoleGetPolicesResponse, role, path=["response"]) - - @parametrize - def test_raw_response_get_polices(self, client: Asktable) -> None: - response = client.roles.with_raw_response.get_polices( - "role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = response.parse() - assert_matches_type(RoleGetPolicesResponse, role, path=["response"]) - - @parametrize - def test_streaming_response_get_polices(self, client: Asktable) -> None: - with client.roles.with_streaming_response.get_polices( - "role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = response.parse() - assert_matches_type(RoleGetPolicesResponse, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_polices(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - client.roles.with_raw_response.get_polices( - "", - ) - - @parametrize - def test_method_get_variables(self, client: Asktable) -> None: - role = client.roles.get_variables( - role_id="role_id", - ) - assert_matches_type(object, role, path=["response"]) - - @parametrize - def test_method_get_variables_with_all_params(self, client: Asktable) -> None: - role = client.roles.get_variables( - role_id="role_id", - bot_id="bot_id", - datasource_ids=["string", "string"], - ) - assert_matches_type(object, role, path=["response"]) - - @parametrize - def test_raw_response_get_variables(self, client: Asktable) -> None: - response = client.roles.with_raw_response.get_variables( - role_id="role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = response.parse() - assert_matches_type(object, role, path=["response"]) - - @parametrize - def test_streaming_response_get_variables(self, client: Asktable) -> None: - with client.roles.with_streaming_response.get_variables( - role_id="role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = response.parse() - assert_matches_type(object, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_variables(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - client.roles.with_raw_response.get_variables( - role_id="", - ) - - -class TestAsyncRoles: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.create( - name="role_name", - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.create( - name="role_name", - policy_ids=["policy_6uOnay1xDNsxLoHmCGf3", "policy_6uOnay1xDNsxLoHmCGf2"], - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.roles.with_raw_response.create( - name="role_name", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = await response.parse() - assert_matches_type(Role, role, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.roles.with_streaming_response.create( - name="role_name", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = await response.parse() - assert_matches_type(Role, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.retrieve( - "role_id", - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.roles.with_raw_response.retrieve( - "role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = await response.parse() - assert_matches_type(Role, role, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.roles.with_streaming_response.retrieve( - "role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = await response.parse() - assert_matches_type(Role, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - await async_client.roles.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.update( - role_id="role_id", - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.update( - role_id="role_id", - name="role_name", - policy_ids=["policy_6uOnay1xDNsxLoHmCGf3", "policy_6uOnay1xDNsxLoHmCGf2"], - ) - assert_matches_type(Role, role, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.roles.with_raw_response.update( - role_id="role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = await response.parse() - assert_matches_type(Role, role, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.roles.with_streaming_response.update( - role_id="role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = await response.parse() - assert_matches_type(Role, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - await async_client.roles.with_raw_response.update( - role_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.list() - assert_matches_type(AsyncPage[Role], role, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.list( - name="name", - page=1, - role_ids=["string", "string"], - size=1, - ) - assert_matches_type(AsyncPage[Role], role, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.roles.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = await response.parse() - assert_matches_type(AsyncPage[Role], role, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.roles.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = await response.parse() - assert_matches_type(AsyncPage[Role], role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.delete( - "role_id", - ) - assert_matches_type(object, role, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.roles.with_raw_response.delete( - "role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = await response.parse() - assert_matches_type(object, role, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.roles.with_streaming_response.delete( - "role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = await response.parse() - assert_matches_type(object, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - await async_client.roles.with_raw_response.delete( - "", - ) - - @parametrize - async def test_method_get_polices(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.get_polices( - "role_id", - ) - assert_matches_type(RoleGetPolicesResponse, role, path=["response"]) - - @parametrize - async def test_raw_response_get_polices(self, async_client: AsyncAsktable) -> None: - response = await async_client.roles.with_raw_response.get_polices( - "role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = await response.parse() - assert_matches_type(RoleGetPolicesResponse, role, path=["response"]) - - @parametrize - async def test_streaming_response_get_polices(self, async_client: AsyncAsktable) -> None: - async with async_client.roles.with_streaming_response.get_polices( - "role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = await response.parse() - assert_matches_type(RoleGetPolicesResponse, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_polices(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - await async_client.roles.with_raw_response.get_polices( - "", - ) - - @parametrize - async def test_method_get_variables(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.get_variables( - role_id="role_id", - ) - assert_matches_type(object, role, path=["response"]) - - @parametrize - async def test_method_get_variables_with_all_params(self, async_client: AsyncAsktable) -> None: - role = await async_client.roles.get_variables( - role_id="role_id", - bot_id="bot_id", - datasource_ids=["string", "string"], - ) - assert_matches_type(object, role, path=["response"]) - - @parametrize - async def test_raw_response_get_variables(self, async_client: AsyncAsktable) -> None: - response = await async_client.roles.with_raw_response.get_variables( - role_id="role_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - role = await response.parse() - assert_matches_type(object, role, path=["response"]) - - @parametrize - async def test_streaming_response_get_variables(self, async_client: AsyncAsktable) -> None: - async with async_client.roles.with_streaming_response.get_variables( - role_id="role_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - role = await response.parse() - assert_matches_type(object, role, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_variables(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `role_id` but received ''"): - await async_client.roles.with_raw_response.get_variables( - role_id="", - ) diff --git a/tests/api_resources/test_scores.py b/tests/api_resources/test_scores.py index c6fcbe86..5d4b2eab 100644 --- a/tests/api_resources/test_scores.py +++ b/tests/api_resources/test_scores.py @@ -9,7 +9,6 @@ from asktable import Asktable, AsyncAsktable from tests.utils import assert_matches_type -from asktable.types import ScoreCreateResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -24,7 +23,7 @@ def test_method_create(self, client: Asktable) -> None: message_id="message_id", score=True, ) - assert_matches_type(ScoreCreateResponse, score, path=["response"]) + assert_matches_type(object, score, path=["response"]) @parametrize def test_raw_response_create(self, client: Asktable) -> None: @@ -37,7 +36,7 @@ def test_raw_response_create(self, client: Asktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" score = response.parse() - assert_matches_type(ScoreCreateResponse, score, path=["response"]) + assert_matches_type(object, score, path=["response"]) @parametrize def test_streaming_response_create(self, client: Asktable) -> None: @@ -50,7 +49,7 @@ def test_streaming_response_create(self, client: Asktable) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" score = response.parse() - assert_matches_type(ScoreCreateResponse, score, path=["response"]) + assert_matches_type(object, score, path=["response"]) assert cast(Any, response.is_closed) is True @@ -67,7 +66,7 @@ async def test_method_create(self, async_client: AsyncAsktable) -> None: message_id="message_id", score=True, ) - assert_matches_type(ScoreCreateResponse, score, path=["response"]) + assert_matches_type(object, score, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: @@ -80,7 +79,7 @@ async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" score = await response.parse() - assert_matches_type(ScoreCreateResponse, score, path=["response"]) + assert_matches_type(object, score, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: @@ -93,6 +92,6 @@ async def test_streaming_response_create(self, async_client: AsyncAsktable) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" score = await response.parse() - assert_matches_type(ScoreCreateResponse, score, path=["response"]) + assert_matches_type(object, score, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_securetunnels.py b/tests/api_resources/test_securetunnels.py deleted file mode 100644 index 8ab246ed..00000000 --- a/tests/api_resources/test_securetunnels.py +++ /dev/null @@ -1,498 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import ( - SecureTunnel, - SecuretunnelListLinksResponse, -) -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestSecuretunnels: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - securetunnel = client.securetunnels.create( - name="我的测试机", - ) - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.securetunnels.with_raw_response.create( - name="我的测试机", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.securetunnels.with_streaming_response.create( - name="我的测试机", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - securetunnel = client.securetunnels.retrieve( - "securetunnel_id", - ) - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.securetunnels.with_raw_response.retrieve( - "securetunnel_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.securetunnels.with_streaming_response.retrieve( - "securetunnel_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `securetunnel_id` but received ''"): - client.securetunnels.with_raw_response.retrieve( - "", - ) - - @parametrize - def test_method_update(self, client: Asktable) -> None: - securetunnel = client.securetunnels.update( - securetunnel_id="securetunnel_id", - ) - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - securetunnel = client.securetunnels.update( - securetunnel_id="securetunnel_id", - client_info={}, - name="我的测试机", - unique_key="unique_key", - ) - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.securetunnels.with_raw_response.update( - securetunnel_id="securetunnel_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.securetunnels.with_streaming_response.update( - securetunnel_id="securetunnel_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `securetunnel_id` but received ''"): - client.securetunnels.with_raw_response.update( - securetunnel_id="", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - securetunnel = client.securetunnels.list() - assert_matches_type(SyncPage[SecureTunnel], securetunnel, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - securetunnel = client.securetunnels.list( - page=1, - size=1, - ) - assert_matches_type(SyncPage[SecureTunnel], securetunnel, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.securetunnels.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = response.parse() - assert_matches_type(SyncPage[SecureTunnel], securetunnel, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.securetunnels.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = response.parse() - assert_matches_type(SyncPage[SecureTunnel], securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - securetunnel = client.securetunnels.delete( - "securetunnel_id", - ) - assert securetunnel is None - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.securetunnels.with_raw_response.delete( - "securetunnel_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = response.parse() - assert securetunnel is None - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.securetunnels.with_streaming_response.delete( - "securetunnel_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = response.parse() - assert securetunnel is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `securetunnel_id` but received ''"): - client.securetunnels.with_raw_response.delete( - "", - ) - - @parametrize - def test_method_list_links(self, client: Asktable) -> None: - securetunnel = client.securetunnels.list_links( - securetunnel_id="securetunnel_id", - ) - assert_matches_type(SyncPage[SecuretunnelListLinksResponse], securetunnel, path=["response"]) - - @parametrize - def test_method_list_links_with_all_params(self, client: Asktable) -> None: - securetunnel = client.securetunnels.list_links( - securetunnel_id="securetunnel_id", - page=1, - size=1, - ) - assert_matches_type(SyncPage[SecuretunnelListLinksResponse], securetunnel, path=["response"]) - - @parametrize - def test_raw_response_list_links(self, client: Asktable) -> None: - response = client.securetunnels.with_raw_response.list_links( - securetunnel_id="securetunnel_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = response.parse() - assert_matches_type(SyncPage[SecuretunnelListLinksResponse], securetunnel, path=["response"]) - - @parametrize - def test_streaming_response_list_links(self, client: Asktable) -> None: - with client.securetunnels.with_streaming_response.list_links( - securetunnel_id="securetunnel_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = response.parse() - assert_matches_type(SyncPage[SecuretunnelListLinksResponse], securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_links(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `securetunnel_id` but received ''"): - client.securetunnels.with_raw_response.list_links( - securetunnel_id="", - ) - - -class TestAsyncSecuretunnels: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.create( - name="我的测试机", - ) - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.securetunnels.with_raw_response.create( - name="我的测试机", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = await response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.securetunnels.with_streaming_response.create( - name="我的测试机", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = await response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.retrieve( - "securetunnel_id", - ) - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.securetunnels.with_raw_response.retrieve( - "securetunnel_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = await response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.securetunnels.with_streaming_response.retrieve( - "securetunnel_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = await response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `securetunnel_id` but received ''"): - await async_client.securetunnels.with_raw_response.retrieve( - "", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.update( - securetunnel_id="securetunnel_id", - ) - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.update( - securetunnel_id="securetunnel_id", - client_info={}, - name="我的测试机", - unique_key="unique_key", - ) - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.securetunnels.with_raw_response.update( - securetunnel_id="securetunnel_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = await response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.securetunnels.with_streaming_response.update( - securetunnel_id="securetunnel_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = await response.parse() - assert_matches_type(SecureTunnel, securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `securetunnel_id` but received ''"): - await async_client.securetunnels.with_raw_response.update( - securetunnel_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.list() - assert_matches_type(AsyncPage[SecureTunnel], securetunnel, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.list( - page=1, - size=1, - ) - assert_matches_type(AsyncPage[SecureTunnel], securetunnel, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.securetunnels.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = await response.parse() - assert_matches_type(AsyncPage[SecureTunnel], securetunnel, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.securetunnels.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = await response.parse() - assert_matches_type(AsyncPage[SecureTunnel], securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.delete( - "securetunnel_id", - ) - assert securetunnel is None - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.securetunnels.with_raw_response.delete( - "securetunnel_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = await response.parse() - assert securetunnel is None - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.securetunnels.with_streaming_response.delete( - "securetunnel_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = await response.parse() - assert securetunnel is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `securetunnel_id` but received ''"): - await async_client.securetunnels.with_raw_response.delete( - "", - ) - - @parametrize - async def test_method_list_links(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.list_links( - securetunnel_id="securetunnel_id", - ) - assert_matches_type(AsyncPage[SecuretunnelListLinksResponse], securetunnel, path=["response"]) - - @parametrize - async def test_method_list_links_with_all_params(self, async_client: AsyncAsktable) -> None: - securetunnel = await async_client.securetunnels.list_links( - securetunnel_id="securetunnel_id", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[SecuretunnelListLinksResponse], securetunnel, path=["response"]) - - @parametrize - async def test_raw_response_list_links(self, async_client: AsyncAsktable) -> None: - response = await async_client.securetunnels.with_raw_response.list_links( - securetunnel_id="securetunnel_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - securetunnel = await response.parse() - assert_matches_type(AsyncPage[SecuretunnelListLinksResponse], securetunnel, path=["response"]) - - @parametrize - async def test_streaming_response_list_links(self, async_client: AsyncAsktable) -> None: - async with async_client.securetunnels.with_streaming_response.list_links( - securetunnel_id="securetunnel_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - securetunnel = await response.parse() - assert_matches_type(AsyncPage[SecuretunnelListLinksResponse], securetunnel, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_links(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `securetunnel_id` but received ''"): - await async_client.securetunnels.with_raw_response.list_links( - securetunnel_id="", - ) diff --git a/tests/api_resources/test_sqls.py b/tests/api_resources/test_sqls.py deleted file mode 100644 index b1f756dc..00000000 --- a/tests/api_resources/test_sqls.py +++ /dev/null @@ -1,183 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import QueryResponse -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestSqls: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - sql = client.sqls.create( - datasource_id="datasource_id", - question="question", - ) - assert_matches_type(QueryResponse, sql, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - sql = client.sqls.create( - datasource_id="datasource_id", - question="question", - parameterize=True, - role_id="role_id", - role_variables={}, - ) - assert_matches_type(QueryResponse, sql, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.sqls.with_raw_response.create( - datasource_id="datasource_id", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - sql = response.parse() - assert_matches_type(QueryResponse, sql, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.sqls.with_streaming_response.create( - datasource_id="datasource_id", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - sql = response.parse() - assert_matches_type(QueryResponse, sql, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Asktable) -> None: - sql = client.sqls.list() - assert_matches_type(SyncPage[QueryResponse], sql, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - sql = client.sqls.list( - datasource_id="datasource_id", - page=1, - size=1, - ) - assert_matches_type(SyncPage[QueryResponse], sql, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.sqls.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - sql = response.parse() - assert_matches_type(SyncPage[QueryResponse], sql, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.sqls.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - sql = response.parse() - assert_matches_type(SyncPage[QueryResponse], sql, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncSqls: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - sql = await async_client.sqls.create( - datasource_id="datasource_id", - question="question", - ) - assert_matches_type(QueryResponse, sql, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - sql = await async_client.sqls.create( - datasource_id="datasource_id", - question="question", - parameterize=True, - role_id="role_id", - role_variables={}, - ) - assert_matches_type(QueryResponse, sql, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.sqls.with_raw_response.create( - datasource_id="datasource_id", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - sql = await response.parse() - assert_matches_type(QueryResponse, sql, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.sqls.with_streaming_response.create( - datasource_id="datasource_id", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - sql = await response.parse() - assert_matches_type(QueryResponse, sql, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - sql = await async_client.sqls.list() - assert_matches_type(AsyncPage[QueryResponse], sql, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - sql = await async_client.sqls.list( - datasource_id="datasource_id", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[QueryResponse], sql, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.sqls.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - sql = await response.parse() - assert_matches_type(AsyncPage[QueryResponse], sql, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.sqls.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - sql = await response.parse() - assert_matches_type(AsyncPage[QueryResponse], sql, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_sys.py b/tests/api_resources/test_sys.py deleted file mode 100644 index 67abf960..00000000 --- a/tests/api_resources/test_sys.py +++ /dev/null @@ -1,88 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import SyUpdateConfigResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestSys: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_update_config(self, client: Asktable) -> None: - sy = client.sys.update_config() - assert_matches_type(SyUpdateConfigResponse, sy, path=["response"]) - - @parametrize - def test_method_update_config_with_all_params(self, client: Asktable) -> None: - sy = client.sys.update_config( - global_table_limit=0, - ) - assert_matches_type(SyUpdateConfigResponse, sy, path=["response"]) - - @parametrize - def test_raw_response_update_config(self, client: Asktable) -> None: - response = client.sys.with_raw_response.update_config() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - sy = response.parse() - assert_matches_type(SyUpdateConfigResponse, sy, path=["response"]) - - @parametrize - def test_streaming_response_update_config(self, client: Asktable) -> None: - with client.sys.with_streaming_response.update_config() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - sy = response.parse() - assert_matches_type(SyUpdateConfigResponse, sy, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncSys: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_update_config(self, async_client: AsyncAsktable) -> None: - sy = await async_client.sys.update_config() - assert_matches_type(SyUpdateConfigResponse, sy, path=["response"]) - - @parametrize - async def test_method_update_config_with_all_params(self, async_client: AsyncAsktable) -> None: - sy = await async_client.sys.update_config( - global_table_limit=0, - ) - assert_matches_type(SyUpdateConfigResponse, sy, path=["response"]) - - @parametrize - async def test_raw_response_update_config(self, async_client: AsyncAsktable) -> None: - response = await async_client.sys.with_raw_response.update_config() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - sy = await response.parse() - assert_matches_type(SyUpdateConfigResponse, sy, path=["response"]) - - @parametrize - async def test_streaming_response_update_config(self, async_client: AsyncAsktable) -> None: - async with async_client.sys.with_streaming_response.update_config() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - sy = await response.parse() - assert_matches_type(SyUpdateConfigResponse, sy, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_trainings.py b/tests/api_resources/test_trainings.py deleted file mode 100644 index 33452ed1..00000000 --- a/tests/api_resources/test_trainings.py +++ /dev/null @@ -1,399 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from asktable import Asktable, AsyncAsktable -from tests.utils import assert_matches_type -from asktable.types import ( - TrainingListResponse, - TrainingCreateResponse, - TrainingUpdateResponse, -) -from asktable.pagination import SyncPage, AsyncPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestTrainings: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - training = client.trainings.create( - datasource_id="datasource_id", - body=[ - { - "question": "question", - "sql": "sql", - } - ], - ) - assert_matches_type(TrainingCreateResponse, training, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.trainings.with_raw_response.create( - datasource_id="datasource_id", - body=[ - { - "question": "question", - "sql": "sql", - } - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - training = response.parse() - assert_matches_type(TrainingCreateResponse, training, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.trainings.with_streaming_response.create( - datasource_id="datasource_id", - body=[ - { - "question": "question", - "sql": "sql", - } - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - training = response.parse() - assert_matches_type(TrainingCreateResponse, training, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update(self, client: Asktable) -> None: - training = client.trainings.update( - id="id", - datasource_id="datasource_id", - ) - assert_matches_type(TrainingUpdateResponse, training, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - training = client.trainings.update( - id="id", - datasource_id="datasource_id", - active=True, - question="question", - role_id="role_id", - sql="sql", - ) - assert_matches_type(TrainingUpdateResponse, training, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.trainings.with_raw_response.update( - id="id", - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - training = response.parse() - assert_matches_type(TrainingUpdateResponse, training, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.trainings.with_streaming_response.update( - id="id", - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - training = response.parse() - assert_matches_type(TrainingUpdateResponse, training, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.trainings.with_raw_response.update( - id="", - datasource_id="datasource_id", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - training = client.trainings.list( - datasource_id="datasource_id", - ) - assert_matches_type(SyncPage[TrainingListResponse], training, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Asktable) -> None: - training = client.trainings.list( - datasource_id="datasource_id", - page=1, - size=1, - ) - assert_matches_type(SyncPage[TrainingListResponse], training, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.trainings.with_raw_response.list( - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - training = response.parse() - assert_matches_type(SyncPage[TrainingListResponse], training, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.trainings.with_streaming_response.list( - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - training = response.parse() - assert_matches_type(SyncPage[TrainingListResponse], training, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - training = client.trainings.delete( - id="id", - datasource_id="datasource_id", - ) - assert_matches_type(object, training, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.trainings.with_raw_response.delete( - id="id", - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - training = response.parse() - assert_matches_type(object, training, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.trainings.with_streaming_response.delete( - id="id", - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - training = response.parse() - assert_matches_type(object, training, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Asktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.trainings.with_raw_response.delete( - id="", - datasource_id="datasource_id", - ) - - -class TestAsyncTrainings: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncAsktable) -> None: - training = await async_client.trainings.create( - datasource_id="datasource_id", - body=[ - { - "question": "question", - "sql": "sql", - } - ], - ) - assert_matches_type(TrainingCreateResponse, training, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.trainings.with_raw_response.create( - datasource_id="datasource_id", - body=[ - { - "question": "question", - "sql": "sql", - } - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - training = await response.parse() - assert_matches_type(TrainingCreateResponse, training, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.trainings.with_streaming_response.create( - datasource_id="datasource_id", - body=[ - { - "question": "question", - "sql": "sql", - } - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - training = await response.parse() - assert_matches_type(TrainingCreateResponse, training, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - training = await async_client.trainings.update( - id="id", - datasource_id="datasource_id", - ) - assert_matches_type(TrainingUpdateResponse, training, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - training = await async_client.trainings.update( - id="id", - datasource_id="datasource_id", - active=True, - question="question", - role_id="role_id", - sql="sql", - ) - assert_matches_type(TrainingUpdateResponse, training, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.trainings.with_raw_response.update( - id="id", - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - training = await response.parse() - assert_matches_type(TrainingUpdateResponse, training, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.trainings.with_streaming_response.update( - id="id", - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - training = await response.parse() - assert_matches_type(TrainingUpdateResponse, training, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.trainings.with_raw_response.update( - id="", - datasource_id="datasource_id", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - training = await async_client.trainings.list( - datasource_id="datasource_id", - ) - assert_matches_type(AsyncPage[TrainingListResponse], training, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncAsktable) -> None: - training = await async_client.trainings.list( - datasource_id="datasource_id", - page=1, - size=1, - ) - assert_matches_type(AsyncPage[TrainingListResponse], training, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.trainings.with_raw_response.list( - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - training = await response.parse() - assert_matches_type(AsyncPage[TrainingListResponse], training, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.trainings.with_streaming_response.list( - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - training = await response.parse() - assert_matches_type(AsyncPage[TrainingListResponse], training, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - training = await async_client.trainings.delete( - id="id", - datasource_id="datasource_id", - ) - assert_matches_type(object, training, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.trainings.with_raw_response.delete( - id="id", - datasource_id="datasource_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - training = await response.parse() - assert_matches_type(object, training, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.trainings.with_streaming_response.delete( - id="id", - datasource_id="datasource_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - training = await response.parse() - assert_matches_type(object, training, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.trainings.with_raw_response.delete( - id="", - datasource_id="datasource_id", - ) diff --git a/tests/test_client.py b/tests/test_client.py index 76c130aa..26c9114a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -6,15 +6,13 @@ import os import sys import json -import time import asyncio import inspect -import subprocess +import dataclasses import tracemalloc -from typing import Any, Union, cast -from textwrap import dedent +from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast from unittest import mock -from typing_extensions import Literal +from typing_extensions import Literal, AsyncIterator, override import httpx import pytest @@ -23,19 +21,23 @@ from asktable import Asktable, AsyncAsktable, APIResponseValidationError from asktable._types import Omit +from asktable._utils import asyncify from asktable._models import BaseModel, FinalRequestOptions from asktable._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError from asktable._base_client import ( DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, + OtherPlatform, DefaultHttpxClient, DefaultAsyncHttpxClient, + get_platform, make_request_options, ) from .utils import update_env +T = TypeVar("T") base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") api_key = "My API Key" @@ -50,6 +52,57 @@ def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float: return 0.1 +def mirror_request_content(request: httpx.Request) -> httpx.Response: + return httpx.Response(200, content=request.content) + + +# note: we can't use the httpx.MockTransport class as it consumes the request +# body itself, which means we can't test that the body is read lazily +class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport): + def __init__( + self, + handler: Callable[[httpx.Request], httpx.Response] + | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]], + ) -> None: + self.handler = handler + + @override + def handle_request( + self, + request: httpx.Request, + ) -> httpx.Response: + assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function" + assert inspect.isfunction(self.handler), "handler must be a function" + return self.handler(request) + + @override + async def handle_async_request( + self, + request: httpx.Request, + ) -> httpx.Response: + assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function" + return await self.handler(request) + + +@dataclasses.dataclass +class Counter: + value: int = 0 + + +def _make_sync_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> Iterator[T]: + for item in iterable: + if counter: + counter.value += 1 + yield item + + +async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> AsyncIterator[T]: + for item in iterable: + if counter: + counter.value += 1 + yield item + + def _get_open_connections(client: Asktable | AsyncAsktable) -> int: transport = client._client._transport assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport) @@ -59,51 +112,49 @@ def _get_open_connections(client: Asktable | AsyncAsktable) -> int: class TestAsktable: - client = Asktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - def test_raw_response(self, respx_mock: MockRouter) -> None: + def test_raw_response(self, respx_mock: MockRouter, client: Asktable) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + def test_raw_response_for_binary(self, respx_mock: MockRouter, client: Asktable) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, client: Asktable) -> None: + copied = client.copy() + assert id(copied) != id(client) - copied = self.client.copy(api_key="another My API Key") + copied = client.copy(api_key="another My API Key") assert copied.api_key == "another My API Key" - assert self.client.api_key == "My API Key" + assert client.api_key == "My API Key" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, client: Asktable) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(client.timeout, httpx.Timeout) + copied = client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(client.timeout, httpx.Timeout) def test_copy_default_headers(self) -> None: client = Asktable( @@ -138,6 +189,7 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + client.close() def test_copy_default_query(self) -> None: client = Asktable( @@ -175,13 +227,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + client.close() + + def test_copy_signature(self, client: Asktable) -> 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. - self.client.__init__, # type: ignore[misc] + client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -192,12 +246,12 @@ def test_copy_signature(self) -> None: assert copy_param is not None, f"copy() signature is missing the {name} param" @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self) -> None: + def test_copy_build_request(self, client: Asktable) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -254,14 +308,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + def test_request_timeout(self, client: Asktable) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( - FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) - ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0))) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(100.0) @@ -274,6 +326,8 @@ def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + client.close() + def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used with httpx.Client(timeout=None) as http_client: @@ -285,6 +339,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + client.close() + # no timeout given to the httpx client should not use the httpx default with httpx.Client() as http_client: client = Asktable( @@ -295,6 +351,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + client.close() + # explicitly passing the default timeout currently results in it being ignored with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = Asktable( @@ -305,6 +363,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + client.close() + async def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): async with httpx.AsyncClient() as http_client: @@ -316,14 +376,14 @@ async def test_invalid_http_client(self) -> None: ) def test_default_headers_option(self) -> None: - client = Asktable( + test_client = Asktable( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = Asktable( + test_client2 = Asktable( base_url=base_url, api_key=api_key, _strict_response_validation=True, @@ -332,10 +392,13 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + test_client.close() + test_client2.close() + def test_default_query_option(self) -> None: client = Asktable( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} @@ -354,8 +417,34 @@ def test_default_query_option(self) -> None: url = httpx.URL(request.url) assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + client.close() + + def test_hardcoded_query_params_in_url(self, client: Asktable) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true")) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/foo?beta=true", + params={"limit": "10", "page": "abc"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"} + + request = client._build_request( + FinalRequestOptions( + method="get", + url="/files/a%2Fb?beta=true", + params={"limit": "10"}, + ) + ) + assert request.url.raw_path == b"/files/a%2Fb?beta=true&limit=10" + + def test_request_extra_json(self, client: Asktable) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -366,7 +455,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -377,7 +466,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -388,8 +477,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: Asktable) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -399,7 +488,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -410,8 +499,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: Asktable) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -424,7 +513,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo"} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -438,7 +527,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2"} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -481,7 +570,71 @@ def test_multipart_repeating_array(self, client: Asktable) -> None: ] @pytest.mark.respx(base_url=base_url) - def test_basic_union_response(self, respx_mock: MockRouter) -> None: + def test_binary_content_upload(self, respx_mock: MockRouter, client: Asktable) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + response = client.post( + "/upload", + content=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + def test_binary_content_upload_with_iterator(self) -> None: + file_content = b"Hello, this is a test file." + counter = Counter() + iterator = _make_sync_iterator([file_content], counter=counter) + + def mock_handler(request: httpx.Request) -> httpx.Response: + assert counter.value == 0, "the request body should not have been read" + return httpx.Response(200, content=request.read()) + + with Asktable( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.Client(transport=MockTransport(handler=mock_handler)), + ) as client: + response = client.post( + "/upload", + content=iterator, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + assert counter.value == 1 + + @pytest.mark.respx(base_url=base_url) + def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: Asktable) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + with pytest.deprecated_call( + match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." + ): + response = client.post( + "/upload", + body=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + @pytest.mark.respx(base_url=base_url) + def test_basic_union_response(self, respx_mock: MockRouter, client: Asktable) -> None: class Model1(BaseModel): name: str @@ -490,12 +643,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + def test_union_response_different_types(self, respx_mock: MockRouter, client: Asktable) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -506,18 +659,18 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter, client: Asktable) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -533,7 +686,7 @@ class Model(BaseModel): ) ) - response = self.client.get("/foo", cast_to=Model) + response = client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 @@ -545,6 +698,8 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" + client.close() + def test_base_url_env(self) -> None: with update_env(ASKTABLE_BASE_URL="http://localhost:5000/from/env"): client = Asktable(api_key=api_key, _strict_response_validation=True) @@ -572,6 +727,7 @@ def test_base_url_trailing_slash(self, client: Asktable) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + client.close() @pytest.mark.parametrize( "client", @@ -595,6 +751,7 @@ def test_base_url_no_trailing_slash(self, client: Asktable) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + client.close() @pytest.mark.parametrize( "client", @@ -618,35 +775,36 @@ def test_absolute_request_url(self, client: Asktable) -> None: ), ) assert request.url == "https://myapi.com/foo" + client.close() def test_copied_client_does_not_close_http(self) -> None: - client = Asktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) - assert not client.is_closed() + test_client = Asktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied - assert not client.is_closed() + assert not test_client.is_closed() def test_client_context_manager(self) -> None: - client = Asktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) - with client as c2: - assert c2 is client + test_client = Asktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) + with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + def test_client_response_validation_error(self, respx_mock: MockRouter, client: Asktable) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - self.client.get("/foo", cast_to=Model) + client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) @@ -666,11 +824,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): strict_client.get("/foo", cast_to=Model) - client = Asktable(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = Asktable(base_url=base_url, api_key=api_key, _strict_response_validation=False) - response = client.get("/foo", cast_to=Model) + response = non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + strict_client.close() + non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -693,9 +854,9 @@ class Model(BaseModel): ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = Asktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) - + def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, client: Asktable + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = client._calculate_retry_timeout(remaining_retries, options, headers) @@ -709,7 +870,7 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, clien with pytest.raises(APITimeoutError): client.datasources.with_streaming_response.create(engine="mysql").__enter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(client) == 0 @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -718,7 +879,7 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client with pytest.raises(APIStatusError): client.datasources.with_streaming_response.create(engine="mysql").__enter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -804,6 +965,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has any proxy env vars set + monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultHttpxClient() @@ -824,83 +993,77 @@ def test_default_client_creation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - def test_follow_redirects(self, respx_mock: MockRouter) -> None: + def test_follow_redirects(self, respx_mock: MockRouter, client: Asktable) -> None: # Test that the default follow_redirects=True allows following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + response = client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.respx(base_url=base_url) - def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + def test_follow_redirects_disabled(self, respx_mock: MockRouter, client: Asktable) -> None: # Test that follow_redirects=False prevents following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) with pytest.raises(APIStatusError) as exc_info: - self.client.post( - "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response - ) + client.post("/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response) assert exc_info.value.response.status_code == 302 assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" class TestAsyncAsktable: - client = AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response(self, respx_mock: MockRouter) -> None: + async def test_raw_response(self, respx_mock: MockRouter, async_client: AsyncAsktable) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + async def test_raw_response_for_binary(self, respx_mock: MockRouter, async_client: AsyncAsktable) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, async_client: AsyncAsktable) -> None: + copied = async_client.copy() + assert id(copied) != id(async_client) - copied = self.client.copy(api_key="another My API Key") + copied = async_client.copy(api_key="another My API Key") assert copied.api_key == "another My API Key" - assert self.client.api_key == "My API Key" + assert async_client.api_key == "My API Key" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, async_client: AsyncAsktable) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = async_client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert async_client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(async_client.timeout, httpx.Timeout) + copied = async_client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(async_client.timeout, httpx.Timeout) - def test_copy_default_headers(self) -> None: + async def test_copy_default_headers(self) -> None: client = AsyncAsktable( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) @@ -933,8 +1096,9 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + await client.close() - def test_copy_default_query(self) -> None: + async def test_copy_default_query(self) -> None: client = AsyncAsktable( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"} ) @@ -970,13 +1134,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + await client.close() + + def test_copy_signature(self, async_client: AsyncAsktable) -> 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. - self.client.__init__, # type: ignore[misc] + async_client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(async_client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -987,12 +1153,12 @@ def test_copy_signature(self) -> None: assert copy_param is not None, f"copy() signature is missing the {name} param" @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self) -> None: + def test_copy_build_request(self, async_client: AsyncAsktable) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = async_client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -1049,12 +1215,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - async def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + async def test_request_timeout(self, async_client: AsyncAsktable) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( + request = async_client._build_request( FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) ) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore @@ -1069,6 +1235,8 @@ async def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + await client.close() + async def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used async with httpx.AsyncClient(timeout=None) as http_client: @@ -1080,6 +1248,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + await client.close() + # no timeout given to the httpx client should not use the httpx default async with httpx.AsyncClient() as http_client: client = AsyncAsktable( @@ -1090,6 +1260,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + await client.close() + # explicitly passing the default timeout currently results in it being ignored async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = AsyncAsktable( @@ -1100,6 +1272,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + await client.close() + def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): with httpx.Client() as http_client: @@ -1110,15 +1284,15 @@ def test_invalid_http_client(self) -> None: http_client=cast(Any, http_client), ) - def test_default_headers_option(self) -> None: - client = AsyncAsktable( + async def test_default_headers_option(self) -> None: + test_client = AsyncAsktable( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = AsyncAsktable( + test_client2 = AsyncAsktable( base_url=base_url, api_key=api_key, _strict_response_validation=True, @@ -1127,11 +1301,14 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" - def test_default_query_option(self) -> None: + await test_client.close() + await test_client2.close() + + async def test_default_query_option(self) -> None: client = AsyncAsktable( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} ) @@ -1149,8 +1326,34 @@ def test_default_query_option(self) -> None: url = httpx.URL(request.url) assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + await client.close() + + async def test_hardcoded_query_params_in_url(self, async_client: AsyncAsktable) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo?beta=true")) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true"} + + request = async_client._build_request( + FinalRequestOptions( + method="get", + url="/foo?beta=true", + params={"limit": "10", "page": "abc"}, + ) + ) + url = httpx.URL(request.url) + assert dict(url.params) == {"beta": "true", "limit": "10", "page": "abc"} + + request = async_client._build_request( + FinalRequestOptions( + method="get", + url="/files/a%2Fb?beta=true", + params={"limit": "10"}, + ) + ) + assert request.url.raw_path == b"/files/a%2Fb?beta=true&limit=10" + + def test_request_extra_json(self, client: Asktable) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1161,7 +1364,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1172,7 +1375,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1183,8 +1386,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: Asktable) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1194,7 +1397,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1205,8 +1408,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: Asktable) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1219,7 +1422,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo"} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1233,7 +1436,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2"} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1276,7 +1479,73 @@ def test_multipart_repeating_array(self, async_client: AsyncAsktable) -> None: ] @pytest.mark.respx(base_url=base_url) - async def test_basic_union_response(self, respx_mock: MockRouter) -> None: + async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncAsktable) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + response = await async_client.post( + "/upload", + content=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + async def test_binary_content_upload_with_asynciterator(self) -> None: + file_content = b"Hello, this is a test file." + counter = Counter() + iterator = _make_async_iterator([file_content], counter=counter) + + async def mock_handler(request: httpx.Request) -> httpx.Response: + assert counter.value == 0, "the request body should not have been read" + return httpx.Response(200, content=await request.aread()) + + async with AsyncAsktable( + base_url=base_url, + api_key=api_key, + _strict_response_validation=True, + http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)), + ) as client: + response = await client.post( + "/upload", + content=iterator, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + assert counter.value == 1 + + @pytest.mark.respx(base_url=base_url) + async def test_binary_content_upload_with_body_is_deprecated( + self, respx_mock: MockRouter, async_client: AsyncAsktable + ) -> None: + respx_mock.post("/upload").mock(side_effect=mirror_request_content) + + file_content = b"Hello, this is a test file." + + with pytest.deprecated_call( + match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." + ): + response = await async_client.post( + "/upload", + body=file_content, + cast_to=httpx.Response, + options={"headers": {"Content-Type": "application/octet-stream"}}, + ) + + assert response.status_code == 200 + assert response.request.headers["Content-Type"] == "application/octet-stream" + assert response.content == file_content + + @pytest.mark.respx(base_url=base_url) + async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncAsktable) -> None: class Model1(BaseModel): name: str @@ -1285,12 +1554,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - async def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + async def test_union_response_different_types(self, respx_mock: MockRouter, async_client: AsyncAsktable) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -1301,18 +1570,20 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - async def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + async def test_non_application_json_content_type_for_json_data( + self, respx_mock: MockRouter, async_client: AsyncAsktable + ) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -1328,11 +1599,11 @@ class Model(BaseModel): ) ) - response = await self.client.get("/foo", cast_to=Model) + response = await async_client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 - def test_base_url_setter(self) -> None: + async def test_base_url_setter(self) -> None: client = AsyncAsktable( base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True ) @@ -1342,7 +1613,9 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" - def test_base_url_env(self) -> None: + await client.close() + + async def test_base_url_env(self) -> None: with update_env(ASKTABLE_BASE_URL="http://localhost:5000/from/env"): client = AsyncAsktable(api_key=api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" @@ -1362,7 +1635,7 @@ def test_base_url_env(self) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_trailing_slash(self, client: AsyncAsktable) -> None: + async def test_base_url_trailing_slash(self, client: AsyncAsktable) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1371,6 +1644,7 @@ def test_base_url_trailing_slash(self, client: AsyncAsktable) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() @pytest.mark.parametrize( "client", @@ -1387,7 +1661,7 @@ def test_base_url_trailing_slash(self, client: AsyncAsktable) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_no_trailing_slash(self, client: AsyncAsktable) -> None: + async def test_base_url_no_trailing_slash(self, client: AsyncAsktable) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1396,6 +1670,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncAsktable) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() @pytest.mark.parametrize( "client", @@ -1412,7 +1687,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncAsktable) -> None: ], ids=["standard", "custom http client"], ) - def test_absolute_request_url(self, client: AsyncAsktable) -> None: + async def test_absolute_request_url(self, client: AsyncAsktable) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1421,37 +1696,37 @@ def test_absolute_request_url(self, client: AsyncAsktable) -> None: ), ) assert request.url == "https://myapi.com/foo" + await client.close() async def test_copied_client_does_not_close_http(self) -> None: - client = AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) - assert not client.is_closed() + test_client = AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied await asyncio.sleep(0.2) - assert not client.is_closed() + assert not test_client.is_closed() async def test_client_context_manager(self) -> None: - client = AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) - async with client as c2: - assert c2 is client + test_client = AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) + async with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + async def test_client_response_validation_error(self, respx_mock: MockRouter, async_client: AsyncAsktable) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - await self.client.get("/foo", cast_to=Model) + await async_client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) @@ -1462,7 +1737,6 @@ async def test_client_max_retries_validation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: class Model(BaseModel): name: str @@ -1474,11 +1748,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): await strict_client.get("/foo", cast_to=Model) - client = AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=False) - response = await client.get("/foo", cast_to=Model) + response = await non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + await strict_client.close() + await non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -1501,13 +1778,12 @@ class Model(BaseModel): ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - @pytest.mark.asyncio - async def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=True) - + async def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, async_client: AsyncAsktable + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) - calculated = client._calculate_retry_timeout(remaining_retries, options, headers) + calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers) assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -1520,7 +1796,7 @@ async def test_retrying_timeout_errors_doesnt_leak( with pytest.raises(APITimeoutError): await async_client.datasources.with_streaming_response.create(engine="mysql").__aenter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(async_client) == 0 @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -1531,12 +1807,11 @@ async def test_retrying_status_errors_doesnt_leak( with pytest.raises(APIStatusError): await async_client.datasources.with_streaming_response.create(engine="mysql").__aenter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(async_client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio @pytest.mark.parametrize("failure_mode", ["status", "exception"]) async def test_retries_taken( self, @@ -1568,7 +1843,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_omit_retry_count_header( self, async_client: AsyncAsktable, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1594,7 +1868,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_overwrite_retry_count_header( self, async_client: AsyncAsktable, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1617,54 +1890,21 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.http_request.headers.get("x-stainless-retry-count") == "42" - def test_get_platform(self) -> None: - # A previous implementation of asyncify could leave threads unterminated when - # used with nest_asyncio. - # - # Since nest_asyncio.apply() is global and cannot be un-applied, this - # test is run in a separate process to avoid affecting other tests. - test_code = dedent(""" - import asyncio - import nest_asyncio - import threading - - from asktable._utils import asyncify - from asktable._base_client import get_platform - - async def test_main() -> None: - result = await asyncify(get_platform)() - print(result) - for thread in threading.enumerate(): - print(thread.name) - - nest_asyncio.apply() - asyncio.run(test_main()) - """) - with subprocess.Popen( - [sys.executable, "-c", test_code], - text=True, - ) as process: - timeout = 10 # seconds - - start_time = time.monotonic() - while True: - return_code = process.poll() - if return_code is not None: - if return_code != 0: - raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") - - # success - break - - if time.monotonic() - start_time > timeout: - process.kill() - raise AssertionError("calling get_platform using asyncify resulted in a hung process") - - time.sleep(0.1) + async def test_get_platform(self) -> None: + platform = await asyncify(get_platform)() + assert isinstance(platform, (str, OtherPlatform)) async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has any proxy env vars set + monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultAsyncHttpxClient() @@ -1685,26 +1925,26 @@ async def test_default_client_creation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects(self, respx_mock: MockRouter) -> None: + async def test_follow_redirects(self, respx_mock: MockRouter, async_client: AsyncAsktable) -> None: # Test that the default follow_redirects=True allows following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_client: AsyncAsktable) -> None: # Test that follow_redirects=False prevents following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) with pytest.raises(APIStatusError) as exc_info: - await self.client.post( + await async_client.post( "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response ) diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py deleted file mode 100644 index 469d7bec..00000000 --- a/tests/test_deepcopy.py +++ /dev/null @@ -1,58 +0,0 @@ -from asktable._utils import deepcopy_minimal - - -def assert_different_identities(obj1: object, obj2: object) -> None: - assert obj1 == obj2 - assert id(obj1) != id(obj2) - - -def test_simple_dict() -> None: - obj1 = {"foo": "bar"} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - - -def test_nested_dict() -> None: - obj1 = {"foo": {"bar": True}} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1["foo"], obj2["foo"]) - - -def test_complex_nested_dict() -> None: - obj1 = {"foo": {"bar": [{"hello": "world"}]}} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1["foo"], obj2["foo"]) - assert_different_identities(obj1["foo"]["bar"], obj2["foo"]["bar"]) - assert_different_identities(obj1["foo"]["bar"][0], obj2["foo"]["bar"][0]) - - -def test_simple_list() -> None: - obj1 = ["a", "b", "c"] - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - - -def test_nested_list() -> None: - obj1 = ["a", [1, 2, 3]] - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1[1], obj2[1]) - - -class MyObject: ... - - -def test_ignores_other_types() -> None: - # custom classes - my_obj = MyObject() - obj1 = {"foo": my_obj} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert obj1["foo"] is my_obj - - # tuples - obj3 = ("a", "b") - obj4 = deepcopy_minimal(obj3) - assert obj3 is obj4 diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py index fa22f0e4..602d004b 100644 --- a/tests/test_extract_files.py +++ b/tests/test_extract_files.py @@ -4,7 +4,7 @@ import pytest -from asktable._types import FileTypes +from asktable._types import FileTypes, ArrayFormat from asktable._utils import extract_files @@ -35,6 +35,12 @@ def test_multiple_files() -> None: assert query == {"documents": [{}, {}]} +def test_top_level_file_array() -> None: + query = {"files": [b"file one", b"file two"], "title": "hello"} + assert extract_files(query, paths=[["files", ""]]) == [("files[]", b"file one"), ("files[]", b"file two")] + assert query == {"title": "hello"} + + @pytest.mark.parametrize( "query,paths,expected", [ @@ -62,3 +68,24 @@ def test_ignores_incorrect_paths( expected: list[tuple[str, FileTypes]], ) -> None: assert extract_files(query, paths=paths) == expected + + +@pytest.mark.parametrize( + "array_format,expected_top_level,expected_nested", + [ + ("brackets", [("files[]", b"a"), ("files[]", b"b")], [("items[][file]", b"a"), ("items[][file]", b"b")]), + ("repeat", [("files", b"a"), ("files", b"b")], [("items[file]", b"a"), ("items[file]", b"b")]), + ("comma", [("files", b"a"), ("files", b"b")], [("items[file]", b"a"), ("items[file]", b"b")]), + ("indices", [("files[0]", b"a"), ("files[1]", b"b")], [("items[0][file]", b"a"), ("items[1][file]", b"b")]), + ], +) +def test_array_format_controls_file_field_names( + array_format: ArrayFormat, + expected_top_level: list[tuple[str, FileTypes]], + expected_nested: list[tuple[str, FileTypes]], +) -> None: + top_level = {"files": [b"a", b"b"]} + assert extract_files(top_level, paths=[["files", ""]], array_format=array_format) == expected_top_level + + nested = {"items": [{"file": b"a"}, {"file": b"b"}]} + assert extract_files(nested, paths=[["items", "", "file"]], array_format=array_format) == expected_nested diff --git a/tests/test_files.py b/tests/test_files.py index 55c2dd1e..5026ff64 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -4,7 +4,8 @@ import pytest from dirty_equals import IsDict, IsList, IsBytes, IsTuple -from asktable._files import to_httpx_files, async_to_httpx_files +from asktable._files import to_httpx_files, deepcopy_with_paths, async_to_httpx_files +from asktable._utils import extract_files readme_path = Path(__file__).parent.parent.joinpath("README.md") @@ -49,3 +50,99 @@ def test_string_not_allowed() -> None: "file": "foo", # type: ignore } ) + + +def assert_different_identities(obj1: object, obj2: object) -> None: + assert obj1 == obj2 + assert obj1 is not obj2 + + +class TestDeepcopyWithPaths: + def test_copies_top_level_dict(self) -> None: + original = {"file": b"data", "other": "value"} + result = deepcopy_with_paths(original, [["file"]]) + assert_different_identities(result, original) + + def test_file_value_is_same_reference(self) -> None: + file_bytes = b"contents" + original = {"file": file_bytes} + result = deepcopy_with_paths(original, [["file"]]) + assert_different_identities(result, original) + assert result["file"] is file_bytes + + def test_list_popped_wholesale(self) -> None: + files = [b"f1", b"f2"] + original = {"files": files, "title": "t"} + result = deepcopy_with_paths(original, [["files", ""]]) + assert_different_identities(result, original) + result_files = result["files"] + assert isinstance(result_files, list) + assert_different_identities(result_files, files) + + def test_nested_array_path_copies_list_and_elements(self) -> None: + elem1 = {"file": b"f1", "extra": 1} + elem2 = {"file": b"f2", "extra": 2} + original = {"items": [elem1, elem2]} + result = deepcopy_with_paths(original, [["items", "", "file"]]) + assert_different_identities(result, original) + result_items = result["items"] + assert isinstance(result_items, list) + assert_different_identities(result_items, original["items"]) + assert_different_identities(result_items[0], elem1) + assert_different_identities(result_items[1], elem2) + + def test_empty_paths_returns_same_object(self) -> None: + original = {"foo": "bar"} + result = deepcopy_with_paths(original, []) + assert result is original + + def test_multiple_paths(self) -> None: + f1 = b"file1" + f2 = b"file2" + original = {"a": f1, "b": f2, "c": "unchanged"} + result = deepcopy_with_paths(original, [["a"], ["b"]]) + assert_different_identities(result, original) + assert result["a"] is f1 + assert result["b"] is f2 + assert result["c"] is original["c"] + + def test_extract_files_does_not_mutate_original_top_level(self) -> None: + file_bytes = b"contents" + original = {"file": file_bytes, "other": "value"} + + copied = deepcopy_with_paths(original, [["file"]]) + extracted = extract_files(copied, paths=[["file"]]) + + assert extracted == [("file", file_bytes)] + assert original == {"file": file_bytes, "other": "value"} + assert copied == {"other": "value"} + + def test_extract_files_does_not_mutate_original_nested_array_path(self) -> None: + file1 = b"f1" + file2 = b"f2" + original = { + "items": [ + {"file": file1, "extra": 1}, + {"file": file2, "extra": 2}, + ], + "title": "example", + } + + copied = deepcopy_with_paths(original, [["items", "", "file"]]) + extracted = extract_files(copied, paths=[["items", "", "file"]]) + + assert [entry for _, entry in extracted] == [file1, file2] + assert original == { + "items": [ + {"file": file1, "extra": 1}, + {"file": file2, "extra": 2}, + ], + "title": "example", + } + assert copied == { + "items": [ + {"extra": 1}, + {"extra": 2}, + ], + "title": "example", + } diff --git a/tests/test_models.py b/tests/test_models.py index 7864490f..40408137 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,15 +1,16 @@ import json -from typing import Any, Dict, List, Union, Optional, cast +from typing import TYPE_CHECKING, Any, Dict, List, Union, Iterable, Optional, cast from datetime import datetime, timezone -from typing_extensions import Literal, Annotated, TypeAliasType +from collections import deque +from typing_extensions import Literal, Annotated, TypedDict, TypeAliasType import pytest import pydantic from pydantic import Field from asktable._utils import PropertyInfo -from asktable._compat import PYDANTIC_V2, parse_obj, model_dump, model_json -from asktable._models import BaseModel, construct_type +from asktable._compat import PYDANTIC_V1, parse_obj, model_dump, model_json +from asktable._models import DISCRIMINATOR_CACHE, BaseModel, EagerIterable, construct_type class BasicModel(BaseModel): @@ -294,12 +295,12 @@ class Model(BaseModel): assert cast(bool, m.foo) is True m = Model.construct(foo={"name": 3}) - if PYDANTIC_V2: - assert isinstance(m.foo, Submodel1) - assert m.foo.name == 3 # type: ignore - else: + if PYDANTIC_V1: assert isinstance(m.foo, Submodel2) assert m.foo.name == "3" + else: + assert isinstance(m.foo, Submodel1) + assert m.foo.name == 3 # type: ignore def test_list_of_unions() -> None: @@ -426,10 +427,10 @@ class Model(BaseModel): expected = datetime(2019, 12, 27, 18, 11, 19, 117000, tzinfo=timezone.utc) - if PYDANTIC_V2: - expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' - else: + if PYDANTIC_V1: expected_json = '{"created_at": "2019-12-27T18:11:19.117000+00:00"}' + else: + expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' model = Model.construct(created_at="2019-12-27T18:11:19.117Z") assert model.created_at == expected @@ -531,7 +532,7 @@ class Model2(BaseModel): assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} assert m4.to_dict(mode="json") == {"created_at": time_str} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_dict(warnings=False) @@ -556,7 +557,7 @@ class Model(BaseModel): assert m3.model_dump() == {"foo": None} assert m3.model_dump(exclude_none=True) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump(round_trip=True) @@ -580,10 +581,10 @@ class Model(BaseModel): assert json.loads(m.to_json()) == {"FOO": "hello"} assert json.loads(m.to_json(use_api_names=False)) == {"foo": "hello"} - if PYDANTIC_V2: - assert m.to_json(indent=None) == '{"FOO":"hello"}' - else: + if PYDANTIC_V1: assert m.to_json(indent=None) == '{"FOO": "hello"}' + else: + assert m.to_json(indent=None) == '{"FOO":"hello"}' m2 = Model() assert json.loads(m2.to_json()) == {} @@ -595,7 +596,7 @@ class Model(BaseModel): assert json.loads(m3.to_json()) == {"FOO": None} assert json.loads(m3.to_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_json(warnings=False) @@ -622,7 +623,7 @@ class Model(BaseModel): assert json.loads(m3.model_dump_json()) == {"foo": None} assert json.loads(m3.model_dump_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump_json(round_trip=True) @@ -679,12 +680,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + if PYDANTIC_V1: # pydantic v1 automatically converts inputs to strings # if the expected type is a str assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] def test_discriminated_unions_unknown_variant() -> None: @@ -768,12 +769,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.foo_type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + if PYDANTIC_V1: # pydantic v1 automatically converts inputs to strings # if the expected type is a str assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] def test_discriminated_unions_overlapping_discriminators_invalid_data() -> None: @@ -809,7 +810,7 @@ class B(BaseModel): UnionType = cast(Any, Union[A, B]) - assert not hasattr(UnionType, "__discriminator__") + assert not DISCRIMINATOR_CACHE.get(UnionType) m = construct_type( value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) @@ -818,7 +819,7 @@ class B(BaseModel): assert m.type == "b" assert m.data == "foo" # type: ignore[comparison-overlap] - discriminator = UnionType.__discriminator__ + discriminator = DISCRIMINATOR_CACHE.get(UnionType) assert discriminator is not None m = construct_type( @@ -830,10 +831,10 @@ class B(BaseModel): # if the discriminator details object stays the same between invocations then # we hit the cache - assert UnionType.__discriminator__ is discriminator + assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator -@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +@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 @@ -849,7 +850,7 @@ class Model(BaseModel): assert m.union == "bar" -@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") def test_field_named_cls() -> None: class Model(BaseModel): cls: str @@ -934,3 +935,83 @@ class Type2(BaseModel): ) assert isinstance(model, Type1) assert isinstance(model.value, InnerType2) + + +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2 for now") +def test_extra_properties() -> None: + class Item(BaseModel): + prop: int + + class Model(BaseModel): + __pydantic_extra__: Dict[str, Item] = Field(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + other: str + + if TYPE_CHECKING: + + def __getattr__(self, attr: str) -> Item: ... + + model = construct_type( + type_=Model, + value={ + "a": {"prop": 1}, + "other": "foo", + }, + ) + assert isinstance(model, Model) + assert model.a.prop == 1 + assert isinstance(model.a, Item) + assert model.other == "foo" + + +# NOTE: Workaround for Pydantic Iterable behavior. +# Iterable fields are replaced with a ValidatorIterator and may be consumed +# during serialization, which can cause subsequent dumps to return empty data. +# See: https://github.com/pydantic/pydantic/issues/9541 +@pytest.mark.parametrize( + "data, expected_validated", + [ + ([1, 2, 3], [1, 2, 3]), + ((1, 2, 3), (1, 2, 3)), + (set([1, 2, 3]), set([1, 2, 3])), + (iter([1, 2, 3]), [1, 2, 3]), + ([], []), + ((x for x in [1, 2, 3]), [1, 2, 3]), + (map(lambda x: x, [1, 2, 3]), [1, 2, 3]), + (frozenset([1, 2, 3]), frozenset([1, 2, 3])), + (deque([1, 2, 3]), deque([1, 2, 3])), + ], + ids=["list", "tuple", "set", "iterator", "empty", "generator", "map", "frozenset", "deque"], +) +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2") +def test_iterable_construction(data: Iterable[int], expected_validated: Iterable[int]) -> None: + class TypeWithIterable(TypedDict): + items: EagerIterable[int] + + class Model(BaseModel): + data: TypeWithIterable + + m = Model.model_validate({"data": {"items": data}}) + assert m.data["items"] == expected_validated + + # Verify repeated dumps don't lose data (the original bug) + assert m.model_dump()["data"]["items"] == list(expected_validated) + assert m.model_dump()["data"]["items"] == list(expected_validated) + + +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2") +def test_iterable_construction_str_falls_back_to_list() -> None: + # str is iterable (over chars), but str(list_of_chars) produces the list's repr + # rather than reconstructing a string from items. We special-case str to fall + # back to list instead of attempting reconstruction. + class TypeWithIterable(TypedDict): + items: EagerIterable[str] + + class Model(BaseModel): + data: TypeWithIterable + + m = Model.model_validate({"data": {"items": "hello"}}) + + # falls back to list of chars rather than calling str(["h", "e", "l", "l", "o"]) + assert m.data["items"] == ["h", "e", "l", "l", "o"] + assert m.model_dump()["data"]["items"] == ["h", "e", "l", "l", "o"] diff --git a/tests/test_transform.py b/tests/test_transform.py index 33ea35d8..35192dc9 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -8,14 +8,14 @@ import pytest -from asktable._types import NOT_GIVEN, Base64FileInput +from asktable._types import Base64FileInput, omit, not_given from asktable._utils import ( PropertyInfo, transform as _transform, parse_datetime, async_transform as _async_transform, ) -from asktable._compat import PYDANTIC_V2 +from asktable._compat import PYDANTIC_V1 from asktable._models import BaseModel _T = TypeVar("_T") @@ -189,7 +189,7 @@ class DateModel(BaseModel): @pytest.mark.asyncio async def test_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - tz = "Z" if PYDANTIC_V2 else "+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] @@ -297,11 +297,11 @@ async def test_pydantic_unknown_field(use_async: bool) -> None: @pytest.mark.asyncio async def test_pydantic_mismatched_types(use_async: bool) -> None: model = MyModel.construct(foo=True) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) assert cast(Any, params) == {"foo": True} @@ -309,11 +309,11 @@ async def test_pydantic_mismatched_types(use_async: bool) -> None: @pytest.mark.asyncio async def test_pydantic_mismatched_object_type(use_async: bool) -> None: model = MyModel.construct(foo=MyModel.construct(hello="world")) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) assert cast(Any, params) == {"foo": {"hello": "world"}} @@ -450,4 +450,11 @@ async def test_transform_skipping(use_async: bool) -> None: @pytest.mark.asyncio async def test_strips_notgiven(use_async: bool) -> None: assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} - assert await transform({"foo_bar": NOT_GIVEN}, Foo1, use_async) == {} + assert await transform({"foo_bar": not_given}, Foo1, use_async) == {} + + +@parametrize +@pytest.mark.asyncio +async def test_strips_omit(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": omit}, Foo1, use_async) == {} diff --git a/tests/test_utils/test_datetime_parse.py b/tests/test_utils/test_datetime_parse.py new file mode 100644 index 00000000..e710e2d2 --- /dev/null +++ b/tests/test_utils/test_datetime_parse.py @@ -0,0 +1,110 @@ +""" +Copied from https://github.com/pydantic/pydantic/blob/v1.10.22/tests/test_datetime_parse.py +with modifications so it works without pydantic v1 imports. +""" + +from typing import Type, Union +from datetime import date, datetime, timezone, timedelta + +import pytest + +from asktable._utils import parse_date, parse_datetime + + +def create_tz(minutes: int) -> timezone: + return timezone(timedelta(minutes=minutes)) + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + ("1494012444.883309", date(2017, 5, 5)), + (b"1494012444.883309", date(2017, 5, 5)), + (1_494_012_444.883_309, date(2017, 5, 5)), + ("1494012444", date(2017, 5, 5)), + (1_494_012_444, date(2017, 5, 5)), + (0, date(1970, 1, 1)), + ("2012-04-23", date(2012, 4, 23)), + (b"2012-04-23", date(2012, 4, 23)), + ("2012-4-9", date(2012, 4, 9)), + (date(2012, 4, 9), date(2012, 4, 9)), + (datetime(2012, 4, 9, 12, 15), date(2012, 4, 9)), + # Invalid inputs + ("x20120423", ValueError), + ("2012-04-56", ValueError), + (19_999_999_999, date(2603, 10, 11)), # just before watershed + (20_000_000_001, date(1970, 8, 20)), # just after watershed + (1_549_316_052, date(2019, 2, 4)), # nowish in s + (1_549_316_052_104, date(2019, 2, 4)), # nowish in ms + (1_549_316_052_104_324, date(2019, 2, 4)), # nowish in μs + (1_549_316_052_104_324_096, date(2019, 2, 4)), # nowish in ns + ("infinity", date(9999, 12, 31)), + ("inf", date(9999, 12, 31)), + (float("inf"), date(9999, 12, 31)), + ("infinity ", date(9999, 12, 31)), + (int("1" + "0" * 100), date(9999, 12, 31)), + (1e1000, date(9999, 12, 31)), + ("-infinity", date(1, 1, 1)), + ("-inf", date(1, 1, 1)), + ("nan", ValueError), + ], +) +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] + with pytest.raises(result): + parse_date(value) + else: + assert parse_date(value) == result + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + # values in seconds + ("1494012444.883309", datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + (1_494_012_444.883_309, datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + ("1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (b"1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (1_494_012_444, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + # values in ms + ("1494012444000.883309", datetime(2017, 5, 5, 19, 27, 24, 883, tzinfo=timezone.utc)), + ("-1494012444000.883309", datetime(1922, 8, 29, 4, 32, 35, 999117, tzinfo=timezone.utc)), + (1_494_012_444_000, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + ("2012-04-23T09:15:00", datetime(2012, 4, 23, 9, 15)), + ("2012-4-9 4:8:16", datetime(2012, 4, 9, 4, 8, 16)), + ("2012-04-23T09:15:00Z", datetime(2012, 4, 23, 9, 15, 0, 0, timezone.utc)), + ("2012-4-9 4:8:16-0320", datetime(2012, 4, 9, 4, 8, 16, 0, create_tz(-200))), + ("2012-04-23T10:20:30.400+02:30", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(150))), + ("2012-04-23T10:20:30.400+02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(120))), + ("2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (b"2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (datetime(2017, 5, 5), datetime(2017, 5, 5)), + (0, datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc)), + # Invalid inputs + ("x20120423091500", ValueError), + ("2012-04-56T09:15:90", ValueError), + ("2012-04-23T11:05:00-25:00", ValueError), + (19_999_999_999, datetime(2603, 10, 11, 11, 33, 19, tzinfo=timezone.utc)), # just before watershed + (20_000_000_001, datetime(1970, 8, 20, 11, 33, 20, 1000, tzinfo=timezone.utc)), # just after watershed + (1_549_316_052, datetime(2019, 2, 4, 21, 34, 12, 0, tzinfo=timezone.utc)), # nowish in s + (1_549_316_052_104, datetime(2019, 2, 4, 21, 34, 12, 104_000, tzinfo=timezone.utc)), # nowish in ms + (1_549_316_052_104_324, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in μs + (1_549_316_052_104_324_096, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in ns + ("infinity", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf ", datetime(9999, 12, 31, 23, 59, 59, 999999)), + (1e50, datetime(9999, 12, 31, 23, 59, 59, 999999)), + (float("inf"), datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("-infinity", datetime(1, 1, 1, 0, 0)), + ("-inf", datetime(1, 1, 1, 0, 0)), + ("nan", ValueError), + ], +) +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] + with pytest.raises(result): + parse_datetime(value) + else: + assert parse_datetime(value) == result diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py new file mode 100644 index 00000000..0f447f23 --- /dev/null +++ b/tests/test_utils/test_json.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +import datetime +from typing import Union + +import pydantic + +from asktable import _compat +from asktable._utils._json import openapi_dumps + + +class TestOpenapiDumps: + def test_basic(self) -> None: + data = {"key": "value", "number": 42} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"key":"value","number":42}' + + def test_datetime_serialization(self) -> None: + dt = datetime.datetime(2023, 1, 1, 12, 0, 0) + data = {"datetime": dt} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"datetime":"2023-01-01T12:00:00"}' + + def test_pydantic_model_serialization(self) -> None: + class User(pydantic.BaseModel): + first_name: str + last_name: str + age: int + + model_instance = User(first_name="John", last_name="Kramer", age=83) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"first_name":"John","last_name":"Kramer","age":83}}' + + def test_pydantic_model_with_default_values(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + score: int = 0 + + model_instance = User(name="Alice") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Alice"}}' + + def test_pydantic_model_with_default_values_overridden(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + + model_instance = User(name="Bob", role="admin", active=False) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Bob","role":"admin","active":false}}' + + def test_pydantic_model_with_alias(self) -> None: + class User(pydantic.BaseModel): + first_name: str = pydantic.Field(alias="firstName") + last_name: str = pydantic.Field(alias="lastName") + + model_instance = User(firstName="John", lastName="Doe") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"firstName":"John","lastName":"Doe"}}' + + def test_pydantic_model_with_alias_and_default(self) -> None: + class User(pydantic.BaseModel): + user_name: str = pydantic.Field(alias="userName") + user_role: str = pydantic.Field(default="member", alias="userRole") + is_active: bool = pydantic.Field(default=True, alias="isActive") + + model_instance = User(userName="charlie") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"charlie"}}' + + model_with_overrides = User(userName="diana", userRole="admin", isActive=False) + data = {"model": model_with_overrides} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"diana","userRole":"admin","isActive":false}}' + + def test_pydantic_model_with_nested_models_and_defaults(self) -> None: + class Address(pydantic.BaseModel): + street: str + city: str = "Unknown" + + class User(pydantic.BaseModel): + name: str + address: Address + verified: bool = False + + if _compat.PYDANTIC_V1: + # to handle forward references in Pydantic v1 + User.update_forward_refs(**locals()) # type: ignore[reportDeprecated] + + address = Address(street="123 Main St") + user = User(name="Diana", address=address) + data = {"user": user} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"user":{"name":"Diana","address":{"street":"123 Main St"}}}' + + address_with_city = Address(street="456 Oak Ave", city="Boston") + user_verified = User(name="Eve", address=address_with_city, verified=True) + data = {"user": user_verified} + json_bytes = openapi_dumps(data) + assert ( + json_bytes == b'{"user":{"name":"Eve","address":{"street":"456 Oak Ave","city":"Boston"},"verified":true}}' + ) + + def test_pydantic_model_with_optional_fields(self) -> None: + class User(pydantic.BaseModel): + name: str + email: Union[str, None] + phone: Union[str, None] + + model_with_none = User(name="Eve", email=None, phone=None) + data = {"model": model_with_none} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Eve","email":null,"phone":null}}' + + model_with_values = User(name="Frank", email="frank@example.com", phone=None) + data = {"model": model_with_values} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Frank","email":"frank@example.com","phone":null}}' diff --git a/tests/test_utils/test_path.py b/tests/test_utils/test_path.py new file mode 100644 index 00000000..1c6c154b --- /dev/null +++ b/tests/test_utils/test_path.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from typing import Any + +import pytest + +from asktable._utils._path import path_template + + +@pytest.mark.parametrize( + "template, kwargs, expected", + [ + ("/v1/{id}", dict(id="abc"), "/v1/abc"), + ("/v1/{a}/{b}", dict(a="x", b="y"), "/v1/x/y"), + ("/v1/{a}{b}/path/{c}?val={d}#{e}", dict(a="x", b="y", c="z", d="u", e="v"), "/v1/xy/path/z?val=u#v"), + ("/{w}/{w}", dict(w="echo"), "/echo/echo"), + ("/v1/static", {}, "/v1/static"), + ("", {}, ""), + ("/v1/?q={n}&count=10", dict(n=42), "/v1/?q=42&count=10"), + ("/v1/{v}", dict(v=None), "/v1/null"), + ("/v1/{v}", dict(v=True), "/v1/true"), + ("/v1/{v}", dict(v=False), "/v1/false"), + ("/v1/{v}", dict(v=".hidden"), "/v1/.hidden"), # dot prefix ok + ("/v1/{v}", dict(v="file.txt"), "/v1/file.txt"), # dot in middle ok + ("/v1/{v}", dict(v="..."), "/v1/..."), # triple dot ok + ("/v1/{a}{b}", dict(a=".", b="txt"), "/v1/.txt"), # dot var combining with adjacent to be ok + ("/items?q={v}#{f}", dict(v=".", f=".."), "/items?q=.#.."), # dots in query/fragment are fine + ( + "/v1/{a}?query={b}", + dict(a="../../other/endpoint", b="a&bad=true"), + "/v1/..%2F..%2Fother%2Fendpoint?query=a%26bad%3Dtrue", + ), + ("/v1/{val}", dict(val="a/b/c"), "/v1/a%2Fb%2Fc"), + ("/v1/{val}", dict(val="a/b/c?query=value"), "/v1/a%2Fb%2Fc%3Fquery=value"), + ("/v1/{val}", dict(val="a/b/c?query=value&bad=true"), "/v1/a%2Fb%2Fc%3Fquery=value&bad=true"), + ("/v1/{val}", dict(val="%20"), "/v1/%2520"), # escapes escape sequences in input + # Query: slash and ? are safe, # is not + ("/items?q={v}", dict(v="a/b"), "/items?q=a/b"), + ("/items?q={v}", dict(v="a?b"), "/items?q=a?b"), + ("/items?q={v}", dict(v="a#b"), "/items?q=a%23b"), + ("/items?q={v}", dict(v="a b"), "/items?q=a%20b"), + # Fragment: slash and ? are safe + ("/docs#{v}", dict(v="a/b"), "/docs#a/b"), + ("/docs#{v}", dict(v="a?b"), "/docs#a?b"), + # Path: slash, ? and # are all encoded + ("/v1/{v}", dict(v="a/b"), "/v1/a%2Fb"), + ("/v1/{v}", dict(v="a?b"), "/v1/a%3Fb"), + ("/v1/{v}", dict(v="a#b"), "/v1/a%23b"), + # same var encoded differently by component + ( + "/v1/{v}?q={v}#{v}", + dict(v="a/b?c#d"), + "/v1/a%2Fb%3Fc%23d?q=a/b?c%23d#a/b?c%23d", + ), + ("/v1/{val}", dict(val="x?admin=true"), "/v1/x%3Fadmin=true"), # query injection + ("/v1/{val}", dict(val="x#admin"), "/v1/x%23admin"), # fragment injection + ], +) +def test_interpolation(template: str, kwargs: dict[str, Any], expected: str) -> None: + assert path_template(template, **kwargs) == expected + + +def test_missing_kwarg_raises_key_error() -> None: + with pytest.raises(KeyError, match="org_id"): + path_template("/v1/{org_id}") + + +@pytest.mark.parametrize( + "template, kwargs", + [ + ("{a}/path", dict(a=".")), + ("{a}/path", dict(a="..")), + ("/v1/{a}", dict(a=".")), + ("/v1/{a}", dict(a="..")), + ("/v1/{a}/path", dict(a=".")), + ("/v1/{a}/path", dict(a="..")), + ("/v1/{a}{b}", dict(a=".", b=".")), # adjacent vars → ".." + ("/v1/{a}.", dict(a=".")), # var + static → ".." + ("/v1/{a}{b}", dict(a="", b=".")), # empty + dot → "." + ("/v1/%2e/{x}", dict(x="ok")), # encoded dot in static text + ("/v1/%2e./{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/.%2E/{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/{v}?q=1", dict(v="..")), + ("/v1/{v}#frag", dict(v="..")), + ], +) +def test_dot_segment_rejected(template: str, kwargs: dict[str, Any]) -> None: + with pytest.raises(ValueError, match="dot-segment"): + path_template(template, **kwargs) diff --git a/tests/utils.py b/tests/utils.py index 7497343a..b84eaf23 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,7 +4,7 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Iterator, cast +from typing import Any, TypeVar, Iterator, Sequence, cast from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type @@ -15,10 +15,11 @@ is_list_type, is_union_type, extract_type_arg, + is_sequence_type, is_annotated_type, is_type_alias_type, ) -from asktable._compat import PYDANTIC_V2, field_outer_type, get_model_fields +from asktable._compat import PYDANTIC_V1, field_outer_type, get_model_fields from asktable._models import BaseModel BaseModelT = TypeVar("BaseModelT", bound=BaseModel) @@ -27,12 +28,12 @@ def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: for name, field in get_model_fields(model).items(): field_value = getattr(value, name) - if PYDANTIC_V2: - allow_none = False - else: + if PYDANTIC_V1: # in v1 nullability was structured differently # https://docs.pydantic.dev/2.0/migration/#required-optional-and-nullable-fields allow_none = getattr(field, "allow_none", False) + else: + allow_none = False assert_matches_type( field_outer_type(field), @@ -71,6 +72,13 @@ def assert_matches_type( if is_list_type(type_): return _assert_list_type(type_, value) + 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 + return + if origin == str: assert isinstance(value, str) elif origin == int: