From 65ea7c536f5fe17dfb13666bf7e37f25bf470bd9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 02:24:49 +0000 Subject: [PATCH 01/35] chore(internal): codegen related update --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7a3d8291..30bce9a7 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,12 @@ pip install asktable The full API of this library can be found in [api.md](api.md). ```python +import os from asktable import Asktable -client = Asktable() +client = Asktable( + api_key=os.environ.get("ASKTABLE_API_KEY"), # This is the default and can be omitted +) datasource = client.datasources.create( engine="mysql", @@ -44,10 +47,13 @@ so that your API Key is not stored in source control. Simply import `AsyncAsktable` instead of `Asktable` and use `await` with each API call: ```python +import os import asyncio from asktable import AsyncAsktable -client = AsyncAsktable() +client = AsyncAsktable( + api_key=os.environ.get("ASKTABLE_API_KEY"), # This is the default and can be omitted +) async def main() -> None: From 7d673d44b295a507ca08ff0982cc5e033893e3d3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 03:31:17 +0000 Subject: [PATCH 02/35] fix(docs/api): remove references to nonexistent types --- api.md | 109 ++++++++++++++++----------------------------------------- 1 file changed, 30 insertions(+), 79 deletions(-) diff --git a/api.md b/api.md index dc8deb6e..eca8c2e3 100644 --- a/api.md +++ b/api.md @@ -11,13 +11,7 @@ from asktable.types import Policy Types: ```python -from asktable.types.sys import ( - APIKey, - ModelGroup, - Project, - ProjectDeleteResponse, - ProjectModelGroupsResponse, -) +from asktable.types.sys import APIKey, ModelGroup, Project, ProjectModelGroupsResponse ``` Methods: @@ -26,7 +20,7 @@ Methods: - client.sys.projects.retrieve(project_id) -> Project - 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.delete(project_id) -> object - client.sys.projects.model_groups() -> ProjectModelGroupsResponse ### APIKeys @@ -34,11 +28,7 @@ Methods: Types: ```python -from asktable.types.sys.projects import ( - APIKeyCreateResponse, - APIKeyListResponse, - APIKeyCreateTokenResponse, -) +from asktable.types.sys.projects import APIKeyCreateResponse, APIKeyListResponse ``` Methods: @@ -46,7 +36,7 @@ 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 +- client.sys.projects.api_keys.create_token(project_id, \*\*params) -> object # Securetunnels @@ -70,12 +60,7 @@ Methods: Types: ```python -from asktable.types import ( - Role, - RoleDeleteResponse, - RoleGetPolicesResponse, - RoleGetVariablesResponse, -) +from asktable.types import Role, RoleGetPolicesResponse ``` Methods: @@ -84,9 +69,9 @@ Methods: - 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.delete(role_id) -> object - client.roles.get_polices(role_id) -> RoleGetPolicesResponse -- client.roles.get_variables(role_id, \*\*params) -> object +- client.roles.get_variables(role_id, \*\*params) -> object # Policies @@ -137,11 +122,7 @@ from asktable.types import ( Index, Meta, DatasourceRetrieveResponse, - DatasourceDeleteResponse, - DatasourceAddFileResponse, - DatasourceDeleteFileResponse, DatasourceRetrieveRuntimeMetaResponse, - DatasourceUpdateFieldResponse, ) ``` @@ -151,59 +132,41 @@ Methods: - client.datasources.retrieve(datasource_id) -> DatasourceRetrieveResponse - client.datasources.update(datasource_id, \*\*params) -> Datasource - client.datasources.list(\*\*params) -> SyncPage[Datasource] -- client.datasources.delete(datasource_id) -> object -- client.datasources.add_file(datasource_id, \*\*params) -> object -- client.datasources.delete_file(file_id, \*, datasource_id) -> object +- client.datasources.delete(datasource_id) -> object +- client.datasources.add_file(datasource_id, \*\*params) -> object +- client.datasources.delete_file(file_id, \*, datasource_id) -> object - client.datasources.retrieve_runtime_meta(datasource_id) -> DatasourceRetrieveRuntimeMetaResponse -- client.datasources.update_field(datasource_id, \*\*params) -> object +- client.datasources.update_field(datasource_id, \*\*params) -> object ## Meta -Types: - -```python -from asktable.types.datasources import MetaCreateResponse, MetaUpdateResponse, MetaAnnotateResponse -``` - Methods: -- client.datasources.meta.create(datasource_id, \*\*params) -> object +- client.datasources.meta.create(datasource_id, \*\*params) -> object - client.datasources.meta.retrieve(datasource_id) -> Meta -- client.datasources.meta.update(datasource_id, \*\*params) -> object -- client.datasources.meta.annotate(datasource_id, \*\*params) -> object +- client.datasources.meta.update(datasource_id, \*\*params) -> object +- client.datasources.meta.annotate(datasource_id, \*\*params) -> object ## UploadParams -Types: - -```python -from asktable.types.datasources import UploadParamCreateResponse -``` - Methods: -- client.datasources.upload_params.create(\*\*params) -> object +- client.datasources.upload_params.create(\*\*params) -> object ## Indexes -Types: - -```python -from asktable.types.datasources import IndexCreateResponse, IndexDeleteResponse -``` - Methods: -- client.datasources.indexes.create(ds_id, \*\*params) -> object +- client.datasources.indexes.create(ds_id, \*\*params) -> object - client.datasources.indexes.list(ds_id, \*\*params) -> SyncPage[Index] -- client.datasources.indexes.delete(index_id, \*, ds_id) -> object +- client.datasources.indexes.delete(index_id, \*, ds_id) -> object # Bots Types: ```python -from asktable.types import Chatbot, BotDeleteResponse, BotInviteResponse +from asktable.types import Chatbot ``` Methods: @@ -212,15 +175,15 @@ Methods: - 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 +- client.bots.delete(bot_id) -> object +- client.bots.invite(bot_id, \*\*params) -> object # Extapis Types: ```python -from asktable.types import Extapi, ExtapiDeleteResponse +from asktable.types import Extapi ``` Methods: @@ -229,7 +192,7 @@ Methods: - client.extapis.retrieve(extapi_id) -> Extapi - client.extapis.update(extapi_id, \*\*params) -> Extapi - client.extapis.list(\*\*params) -> SyncPage[Extapi] -- client.extapis.delete(extapi_id) -> object +- client.extapis.delete(extapi_id) -> object ## Routes @@ -252,12 +215,12 @@ Methods: Types: ```python -from asktable.types import AuthCreateTokenResponse, AuthMeResponse +from asktable.types import AuthMeResponse ``` Methods: -- client.auth.create_token(\*\*params) -> object +- client.auth.create_token(\*\*params) -> object - client.auth.me() -> AuthMeResponse # Answers @@ -310,12 +273,7 @@ Methods: Types: ```python -from asktable.types import ( - Entry, - EntryWithDefinition, - BusinessGlossaryCreateResponse, - BusinessGlossaryDeleteResponse, -) +from asktable.types import Entry, EntryWithDefinition, BusinessGlossaryCreateResponse ``` Methods: @@ -324,7 +282,7 @@ Methods: - 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 +- client.business_glossary.delete(entry_id) -> object # Preferences @@ -335,7 +293,6 @@ from asktable.types import ( PreferenceCreateResponse, PreferenceRetrieveResponse, PreferenceUpdateResponse, - PreferenceDeleteResponse, ) ``` @@ -344,21 +301,21 @@ Methods: - client.preferences.create(\*\*params) -> PreferenceCreateResponse - client.preferences.retrieve() -> PreferenceRetrieveResponse - client.preferences.update(\*\*params) -> PreferenceUpdateResponse -- client.preferences.delete() -> object +- client.preferences.delete() -> object # Trainings Types: ```python -from asktable.types import TrainingCreateResponse, TrainingListResponse, TrainingDeleteResponse +from asktable.types import TrainingCreateResponse, TrainingListResponse ``` Methods: - client.trainings.create(\*\*params) -> TrainingCreateResponse - client.trainings.list(\*\*params) -> SyncPage[TrainingListResponse] -- client.trainings.delete(id, \*\*params) -> object +- client.trainings.delete(id, \*\*params) -> object # Project @@ -388,15 +345,9 @@ Methods: # Files -Types: - -```python -from asktable.types import FileRetrieveResponse -``` - Methods: -- client.files.retrieve(file_id) -> object +- client.files.retrieve(file_id) -> object # Dataframes From e003bb1ffd598d1bebf6cbd6859731525632d40e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 14:20:44 +0000 Subject: [PATCH 03/35] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 499f0df9..c961df2b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 96 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-fd9a749a4afed8a45757ab4e83984c36c56cf6f4f0d53b80d4d5e0022869c3e1.yml -openapi_spec_hash: d5cf0471c4e715bdfbf597de3f591ef1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-07276a37af9e3d76eb6ba4a252dddfd1597c779b19f900943a5bee50c33b7b78.yml +openapi_spec_hash: c6527736f0096b46133a02ebe4d56a4b config_hash: a572ab842ea60ce13f1d1a1358440cbe From 4d3aa06c066357059ea1dd4c6d3a75d24cbe8cf6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 07:20:38 +0000 Subject: [PATCH 04/35] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index c961df2b..cb97fe66 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 96 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-07276a37af9e3d76eb6ba4a252dddfd1597c779b19f900943a5bee50c33b7b78.yml -openapi_spec_hash: c6527736f0096b46133a02ebe4d56a4b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-61144c303e908533028ddd3a4cd877f2f5e95e43cb88ea4f75893d5e62932ecd.yml +openapi_spec_hash: 03cef1f606d1352ae3cd0a5e57ae2c92 config_hash: a572ab842ea60ce13f1d1a1358440cbe From c9bd90510f68452335931d54e96ba350741b2f28 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 10:20:56 +0000 Subject: [PATCH 05/35] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index cb97fe66..22459245 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 96 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-61144c303e908533028ddd3a4cd877f2f5e95e43cb88ea4f75893d5e62932ecd.yml -openapi_spec_hash: 03cef1f606d1352ae3cd0a5e57ae2c92 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-ac5ecff5cf03e9713d63470d36dd93cb6c7d466a516bd85e5ec4548c0933b398.yml +openapi_spec_hash: 8f4e83f3dcefba7a1b451b6949b78539 config_hash: a572ab842ea60ce13f1d1a1358440cbe From 9fc4749e8965d398f281078e14f0249d12571ace Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 02:26:54 +0000 Subject: [PATCH 06/35] chore(docs): remove reference to rye shell --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e5bb78fb..58c9d1e9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,8 +17,7 @@ $ rye sync --all-features You can then run scripts using `rye run python script.py` or by activating the virtual environment: ```sh -$ rye shell -# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work +# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work $ source .venv/bin/activate # now you can omit the `rye run` prefix From d2875f3438404557c839e0d158a2e573c3607f1f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 02:39:10 +0000 Subject: [PATCH 07/35] chore(docs): remove unnecessary param examples --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 30bce9a7..179f81d6 100644 --- a/README.md +++ b/README.md @@ -151,10 +151,7 @@ client = Asktable() response = client.sys.projects.api_keys.create_token( project_id="project_id", - chat_role={ - "role_id": "1", - "role_variables": {"id": "42"}, - }, + chat_role={}, ) print(response.chat_role) ``` From b22320bad43f0de89af6d252c36902b2cd08ec97 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 03:42:39 +0000 Subject: [PATCH 08/35] feat(client): add follow_redirects request option --- src/asktable/_base_client.py | 6 ++++ src/asktable/_models.py | 2 ++ src/asktable/_types.py | 2 ++ tests/test_client.py | 54 ++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/src/asktable/_base_client.py b/src/asktable/_base_client.py index 5d4a145a..a705a524 100644 --- a/src/asktable/_base_client.py +++ b/src/asktable/_base_client.py @@ -960,6 +960,9 @@ def request( if self.custom_auth is not None: kwargs["auth"] = self.custom_auth + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + log.debug("Sending HTTP Request: %s %s", request.method, request.url) response = None @@ -1460,6 +1463,9 @@ async def request( if self.custom_auth is not None: kwargs["auth"] = self.custom_auth + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + log.debug("Sending HTTP Request: %s %s", request.method, request.url) response = None diff --git a/src/asktable/_models.py b/src/asktable/_models.py index 798956f1..4f214980 100644 --- a/src/asktable/_models.py +++ b/src/asktable/_models.py @@ -737,6 +737,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): idempotency_key: str json_data: Body extra_json: AnyMapping + follow_redirects: bool @final @@ -750,6 +751,7 @@ class FinalRequestOptions(pydantic.BaseModel): files: Union[HttpxRequestFiles, None] = None idempotency_key: Union[str, None] = None post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() + follow_redirects: Union[bool, None] = None # It should be noted that we cannot use `json` here as that would override # a BaseModel method in an incompatible fashion. diff --git a/src/asktable/_types.py b/src/asktable/_types.py index 6bc9be4a..6a08b156 100644 --- a/src/asktable/_types.py +++ b/src/asktable/_types.py @@ -100,6 +100,7 @@ class RequestOptions(TypedDict, total=False): params: Query extra_json: AnyMapping idempotency_key: str + follow_redirects: bool # Sentinel class used until PEP 0661 is accepted @@ -215,3 +216,4 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth + follow_redirects: bool diff --git a/tests/test_client.py b/tests/test_client.py index 0b8079fb..b0eedec8 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -812,6 +812,33 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.http_request.headers.get("x-stainless-retry-count") == "42" + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects(self, respx_mock: MockRouter) -> 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) + 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: + # 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 + ) + + 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) @@ -1629,3 +1656,30 @@ async def test_main() -> None: raise AssertionError("calling get_platform using asyncify resulted in a hung process") time.sleep(0.1) + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects(self, respx_mock: MockRouter) -> 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) + 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: + # 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( + "/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" From d7a73bceb38896da2565dd7e1ae8a3e39529a685 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 08:20:49 +0000 Subject: [PATCH 09/35] feat(api): api update --- .stats.yml | 4 +-- src/asktable/resources/bots.py | 18 ++++++++++++- src/asktable/types/bot_create_params.py | 21 ++++++++++++--- src/asktable/types/bot_update_params.py | 21 ++++++++++++--- src/asktable/types/chatbot.py | 18 ++++++++++++- tests/api_resources/test_bots.py | 36 +++++++++++++++++++++++++ 6 files changed, 108 insertions(+), 10 deletions(-) diff --git a/.stats.yml b/.stats.yml index 22459245..05b47f71 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 96 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-ac5ecff5cf03e9713d63470d36dd93cb6c7d466a516bd85e5ec4548c0933b398.yml -openapi_spec_hash: 8f4e83f3dcefba7a1b451b6949b78539 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-3e1e26e4e4e25828b277b8b446dffd813a5ef1391e62880b526c16a7cd7622ef.yml +openapi_spec_hash: dce6087693b8f3758dfc694c7e1b1c7a config_hash: a572ab842ea60ce13f1d1a1358440cbe diff --git a/src/asktable/resources/bots.py b/src/asktable/resources/bots.py index 13932733..a64fb2d0 100644 --- a/src/asktable/resources/bots.py +++ b/src/asktable/resources/bots.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Optional +from typing import List, Iterable, Optional import httpx @@ -52,6 +52,7 @@ def create( 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, @@ -80,6 +81,8 @@ def create( extapi_ids: 扩展 API ID 列表,扩展 API ID 的逗号分隔列表。 + interaction_rules: 交互规则列表,用于定义 bot 的行为规则 + magic_input: 魔法提示词 max_rows: 最大返回行数,默认不限制 @@ -111,6 +114,7 @@ def create( "color_theme": color_theme, "debug": debug, "extapi_ids": extapi_ids, + "interaction_rules": interaction_rules, "magic_input": magic_input, "max_rows": max_rows, "publish": publish, @@ -169,6 +173,7 @@ def update( 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, @@ -198,6 +203,8 @@ def update( extapi_ids: 扩展 API ID 列表,扩展 API ID 的逗号分隔列表。 + interaction_rules: 交互规则列表,用于定义 bot 的行为规则 + magic_input: 魔法提示词 max_rows: 最大返回行数,默认不限制 @@ -233,6 +240,7 @@ def update( "datasource_ids": datasource_ids, "debug": debug, "extapi_ids": extapi_ids, + "interaction_rules": interaction_rules, "magic_input": magic_input, "max_rows": max_rows, "name": name, @@ -405,6 +413,7 @@ async def create( 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, @@ -433,6 +442,8 @@ async def create( extapi_ids: 扩展 API ID 列表,扩展 API ID 的逗号分隔列表。 + interaction_rules: 交互规则列表,用于定义 bot 的行为规则 + magic_input: 魔法提示词 max_rows: 最大返回行数,默认不限制 @@ -464,6 +475,7 @@ async def create( "color_theme": color_theme, "debug": debug, "extapi_ids": extapi_ids, + "interaction_rules": interaction_rules, "magic_input": magic_input, "max_rows": max_rows, "publish": publish, @@ -522,6 +534,7 @@ async def update( 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, @@ -551,6 +564,8 @@ async def update( extapi_ids: 扩展 API ID 列表,扩展 API ID 的逗号分隔列表。 + interaction_rules: 交互规则列表,用于定义 bot 的行为规则 + magic_input: 魔法提示词 max_rows: 最大返回行数,默认不限制 @@ -586,6 +601,7 @@ async def update( "datasource_ids": datasource_ids, "debug": debug, "extapi_ids": extapi_ids, + "interaction_rules": interaction_rules, "magic_input": magic_input, "max_rows": max_rows, "name": name, diff --git a/src/asktable/types/bot_create_params.py b/src/asktable/types/bot_create_params.py index 7e0ada9e..e2a2f550 100644 --- a/src/asktable/types/bot_create_params.py +++ b/src/asktable/types/bot_create_params.py @@ -2,10 +2,10 @@ from __future__ import annotations -from typing import List, Optional -from typing_extensions import Required, TypedDict +from typing import List, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict -__all__ = ["BotCreateParams"] +__all__ = ["BotCreateParams", "InteractionRule"] class BotCreateParams(TypedDict, total=False): @@ -24,6 +24,9 @@ class BotCreateParams(TypedDict, total=False): extapi_ids: List[str] """扩展 API ID 列表,扩展 API ID 的逗号分隔列表。""" + interaction_rules: Iterable[InteractionRule] + """交互规则列表,用于定义 bot 的行为规则""" + magic_input: Optional[str] """魔法提示词""" @@ -44,3 +47,15 @@ class BotCreateParams(TypedDict, total=False): 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_update_params.py b/src/asktable/types/bot_update_params.py index e5946079..e08d5a37 100644 --- a/src/asktable/types/bot_update_params.py +++ b/src/asktable/types/bot_update_params.py @@ -2,10 +2,10 @@ from __future__ import annotations -from typing import List, Optional -from typing_extensions import TypedDict +from typing import List, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict -__all__ = ["BotUpdateParams"] +__all__ = ["BotUpdateParams", "InteractionRule"] class BotUpdateParams(TypedDict, total=False): @@ -24,6 +24,9 @@ class BotUpdateParams(TypedDict, total=False): extapi_ids: Optional[List[str]] """扩展 API ID 列表,扩展 API ID 的逗号分隔列表。""" + interaction_rules: Optional[Iterable[InteractionRule]] + """交互规则列表,用于定义 bot 的行为规则""" + magic_input: Optional[str] """魔法提示词""" @@ -47,3 +50,15 @@ class BotUpdateParams(TypedDict, total=False): 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/chatbot.py b/src/asktable/types/chatbot.py index 5f86403e..2c37b41b 100644 --- a/src/asktable/types/chatbot.py +++ b/src/asktable/types/chatbot.py @@ -2,10 +2,23 @@ from typing import List, Optional from datetime import datetime +from typing_extensions import Literal from .._models import BaseModel -__all__ = ["Chatbot"] +__all__ = ["Chatbot", "InteractionRule"] + + +class InteractionRule(BaseModel): + enabled: bool + + message: str + + name: str + + version: Literal["1.0.0"] + + words: List[str] class Chatbot(BaseModel): @@ -35,6 +48,9 @@ class Chatbot(BaseModel): extapi_ids: Optional[List[str]] = None """扩展 API ID 列表,扩展 API ID 的逗号分隔列表。""" + interaction_rules: Optional[List[InteractionRule]] = None + """交互规则列表,用于定义 bot 的行为规则""" + magic_input: Optional[str] = None """魔法提示词""" diff --git a/tests/api_resources/test_bots.py b/tests/api_resources/test_bots.py index 787b84d8..015f76df 100644 --- a/tests/api_resources/test_bots.py +++ b/tests/api_resources/test_bots.py @@ -34,6 +34,15 @@ def test_method_create_with_all_params(self, client: Asktable) -> None: 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, @@ -124,6 +133,15 @@ def test_method_update_with_all_params(self, client: Asktable) -> None: 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", @@ -301,6 +319,15 @@ async def test_method_create_with_all_params(self, async_client: AsyncAsktable) 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, @@ -391,6 +418,15 @@ async def test_method_update_with_all_params(self, async_client: AsyncAsktable) 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", From 652a9571e55cbadf378ce8c28db4c16e880c52f3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 03:32:30 +0000 Subject: [PATCH 10/35] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 05b47f71..f3c7e7e0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 96 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-3e1e26e4e4e25828b277b8b446dffd813a5ef1391e62880b526c16a7cd7622ef.yml -openapi_spec_hash: dce6087693b8f3758dfc694c7e1b1c7a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-66763c323b003a16c4b3adc5cc14d1f4e4b02ccddc3c2dbbebff70ae6a90f753.yml +openapi_spec_hash: 048225c24d300aab5562eb916c4172b8 config_hash: a572ab842ea60ce13f1d1a1358440cbe From 9d9d65e5be80faba732cd2d29854186ff565b4c7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 02:12:58 +0000 Subject: [PATCH 11/35] chore(tests): run tests in parallel --- pyproject.toml | 3 ++- requirements-dev.lock | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c1ce99ea..9a903290 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ dev-dependencies = [ "importlib-metadata>=6.7.0", "rich>=13.7.1", "nest_asyncio==1.6.0", + "pytest-xdist>=3.6.1", ] [tool.rye.scripts] @@ -125,7 +126,7 @@ replacement = '[\1](https://github.com/DataMini/asktable-python/tree/main/\g<2>) [tool.pytest.ini_options] testpaths = ["tests"] -addopts = "--tb=short" +addopts = "--tb=short -n auto" xfail_strict = true asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" diff --git a/requirements-dev.lock b/requirements-dev.lock index 19fed616..8877384b 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -30,6 +30,8 @@ distro==1.8.0 exceptiongroup==1.2.2 # via anyio # via pytest +execnet==2.1.1 + # via pytest-xdist filelock==3.12.4 # via virtualenv h11==0.14.0 @@ -72,7 +74,9 @@ pygments==2.18.0 pyright==1.1.399 pytest==8.3.3 # via pytest-asyncio + # via pytest-xdist pytest-asyncio==0.24.0 +pytest-xdist==3.7.0 python-dateutil==2.8.2 # via time-machine pytz==2023.3.post1 From 03552e74ca1fa48289b48381777b1243398777bc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 02:24:50 +0000 Subject: [PATCH 12/35] fix(pagination): correct next page check --- src/asktable/pagination.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/asktable/pagination.py b/src/asktable/pagination.py index 8e487278..72ee6f2e 100644 --- a/src/asktable/pagination.py +++ b/src/asktable/pagination.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Generic, TypeVar, Optional, cast +from typing import List, Generic, TypeVar, Optional from typing_extensions import override from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage @@ -29,9 +29,8 @@ def next_page_info(self) -> Optional[PageInfo]: if current_page is None: current_page = 1 - last_page = cast("int | None", self._options.params.get("page")) - if last_page is not None and current_page <= last_page: - # The API didn't return a new page in the last request + total_pages = self.pages + if total_pages is not None and current_page >= total_pages: return None return PageInfo(params={"page": current_page + 1}) @@ -56,9 +55,8 @@ def next_page_info(self) -> Optional[PageInfo]: if current_page is None: current_page = 1 - last_page = cast("int | None", self._options.params.get("page")) - if last_page is not None and current_page <= last_page: - # The API didn't return a new page in the last request + total_pages = self.pages + if total_pages is not None and current_page >= total_pages: return None return PageInfo(params={"page": current_page + 1}) From 5568773fc1b6ee7a5183cd5e6789ce6eafe119e8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 02:37:26 +0000 Subject: [PATCH 13/35] fix(client): correctly parse binary response | stream --- src/asktable/_base_client.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/asktable/_base_client.py b/src/asktable/_base_client.py index a705a524..8d24ebe9 100644 --- a/src/asktable/_base_client.py +++ b/src/asktable/_base_client.py @@ -1071,7 +1071,14 @@ def _process_response( ) -> ResponseT: origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, APIResponse): raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") @@ -1574,7 +1581,14 @@ async def _process_response( ) -> ResponseT: origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, AsyncAPIResponse): raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") From c620e09f4be03fabc31167839018e69b8d7f5d7b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 02:43:07 +0000 Subject: [PATCH 14/35] chore(tests): add tests for httpx client instantiation & proxies --- tests/test_client.py | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index b0eedec8..5fcc1d83 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -31,6 +31,8 @@ DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, + DefaultHttpxClient, + DefaultAsyncHttpxClient, make_request_options, ) from asktable.types.datasource_create_params import DatasourceCreateParams @@ -812,6 +814,28 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.http_request.headers.get("x-stainless-retry-count") == "42" + 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") + + client = DefaultHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + @pytest.mark.respx(base_url=base_url) def test_follow_redirects(self, respx_mock: MockRouter) -> None: # Test that the default follow_redirects=True allows following redirects @@ -1657,6 +1681,28 @@ async def test_main() -> None: time.sleep(0.1) + 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") + + client = DefaultAsyncHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + async def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultAsyncHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + @pytest.mark.respx(base_url=base_url) async def test_follow_redirects(self, respx_mock: MockRouter) -> None: # Test that the default follow_redirects=True allows following redirects From f06435ded63522ac7f30d47b560183b86e95ef27 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 04:12:59 +0000 Subject: [PATCH 15/35] chore(internal): update conftest.py --- tests/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index fe426c1f..7d29f540 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + from __future__ import annotations import os From a6636e7b8409f7750b52c4850f05be437e4ed31d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 06:44:00 +0000 Subject: [PATCH 16/35] chore(ci): enable for pull requests --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4631164a..a69511ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: - 'integrated/**' - 'stl-preview-head/**' - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: From bc281028397ea60d93f86ea563e3e9cba303b0c6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 02:15:50 +0000 Subject: [PATCH 17/35] chore(readme): update badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 179f81d6..5b9bd839 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Asktable Python API library -[![PyPI version](https://img.shields.io/pypi/v/asktable.svg)](https://pypi.org/project/asktable/) +[![PyPI version]()](https://pypi.org/project/asktable/) The Asktable Python library provides convenient access to the Asktable REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, From 3036c4bdbe59cd13bdfacdd113478e3e6ddd8ca0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 05:52:40 +0000 Subject: [PATCH 18/35] fix(tests): fix: tests which call HTTP endpoints directly with the example parameters --- tests/test_client.py | 45 ++++++++++++-------------------------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 5fcc1d83..a8031ab6 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,9 +23,7 @@ from asktable import Asktable, AsyncAsktable, APIResponseValidationError from asktable._types import Omit -from asktable._utils import maybe_transform from asktable._models import BaseModel, FinalRequestOptions -from asktable._constants import RAW_RESPONSE_HEADER from asktable._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError from asktable._base_client import ( DEFAULT_TIMEOUT, @@ -35,7 +33,6 @@ DefaultAsyncHttpxClient, make_request_options, ) -from asktable.types.datasource_create_params import DatasourceCreateParams from .utils import update_env @@ -705,32 +702,21 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Asktable) -> None: respx_mock.post("/v1/datasources").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - self.client.post( - "/v1/datasources", - body=cast(object, maybe_transform(dict(engine="mysql"), DatasourceCreateParams)), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + client.datasources.with_streaming_response.create(engine="mysql").__enter__() assert _get_open_connections(self.client) == 0 @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Asktable) -> None: respx_mock.post("/v1/datasources").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - self.client.post( - "/v1/datasources", - body=cast(object, maybe_transform(dict(engine="mysql"), DatasourceCreateParams)), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + client.datasources.with_streaming_response.create(engine="mysql").__enter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -1524,32 +1510,25 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_timeout_errors_doesnt_leak( + self, respx_mock: MockRouter, async_client: AsyncAsktable + ) -> None: respx_mock.post("/v1/datasources").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - await self.client.post( - "/v1/datasources", - body=cast(object, maybe_transform(dict(engine="mysql"), DatasourceCreateParams)), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + await async_client.datasources.with_streaming_response.create(engine="mysql").__aenter__() assert _get_open_connections(self.client) == 0 @mock.patch("asktable._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_status_errors_doesnt_leak( + self, respx_mock: MockRouter, async_client: AsyncAsktable + ) -> None: respx_mock.post("/v1/datasources").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - await self.client.post( - "/v1/datasources", - body=cast(object, maybe_transform(dict(engine="mysql"), DatasourceCreateParams)), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + await async_client.datasources.with_streaming_response.create(engine="mysql").__aenter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) From 482e328e4938b04c3eca656984857d2ffc302fa3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Jun 2025 02:53:59 +0000 Subject: [PATCH 19/35] docs(client): fix httpx.Timeout documentation reference --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b9bd839..a3220fcd 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,7 @@ client.with_options(max_retries=5).datasources.create( ### Timeouts By default requests time out after 5 minutes. You can configure this with a `timeout` option, -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object: +which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: ```python from asktable import Asktable From 292b89e54d3215237251f84ebbae97d4cbf65310 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Jun 2025 04:12:38 +0000 Subject: [PATCH 20/35] feat(client): add support for aiohttp --- README.md | 34 +++++++++++++++ pyproject.toml | 2 + requirements-dev.lock | 27 ++++++++++++ requirements.lock | 27 ++++++++++++ src/asktable/__init__.py | 3 +- src/asktable/_base_client.py | 22 ++++++++++ tests/api_resources/chats/test_messages.py | 4 +- .../api_resources/datasources/test_indexes.py | 4 +- tests/api_resources/datasources/test_meta.py | 4 +- .../datasources/test_upload_params.py | 4 +- tests/api_resources/extapis/test_routes.py | 4 +- .../sys/projects/test_api_keys.py | 4 +- tests/api_resources/sys/test_projects.py | 4 +- tests/api_resources/test_answers.py | 4 +- tests/api_resources/test_auth.py | 4 +- tests/api_resources/test_bots.py | 4 +- tests/api_resources/test_business_glossary.py | 4 +- tests/api_resources/test_caches.py | 4 +- tests/api_resources/test_chats.py | 4 +- tests/api_resources/test_dataframes.py | 4 +- tests/api_resources/test_datasources.py | 4 +- tests/api_resources/test_extapis.py | 4 +- tests/api_resources/test_files.py | 4 +- tests/api_resources/test_integration.py | 4 +- tests/api_resources/test_policies.py | 4 +- tests/api_resources/test_polish.py | 4 +- tests/api_resources/test_preferences.py | 4 +- tests/api_resources/test_project.py | 4 +- tests/api_resources/test_roles.py | 4 +- tests/api_resources/test_scores.py | 4 +- tests/api_resources/test_securetunnels.py | 4 +- tests/api_resources/test_sqls.py | 4 +- tests/api_resources/test_trainings.py | 4 +- tests/conftest.py | 43 ++++++++++++++++--- 34 files changed, 232 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index a3220fcd..c5deedae 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,40 @@ asyncio.run(main()) Functionality between the synchronous and asynchronous clients is otherwise identical. +### With aiohttp + +By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. + +You can enable this by installing `aiohttp`: + +```sh +# install from PyPI +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 + + +async def main() -> None: + async with AsyncAsktable( + 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( + engine="mysql", + ) + print(datasource.id) + + +asyncio.run(main()) +``` + ## Using types Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: diff --git a/pyproject.toml b/pyproject.toml index 9a903290..bffcba11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,8 @@ classifiers = [ Homepage = "https://github.com/DataMini/asktable-python" Repository = "https://github.com/DataMini/asktable-python" +[project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] [tool.rye] managed = true diff --git a/requirements-dev.lock b/requirements-dev.lock index 8877384b..8628ca16 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -10,6 +10,13 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via asktable + # via httpx-aiohttp +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.4.0 @@ -17,6 +24,10 @@ anyio==4.4.0 # via httpx argcomplete==3.1.2 # via nox +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -34,16 +45,23 @@ execnet==2.1.1 # via pytest-xdist filelock==3.12.4 # via virtualenv +frozenlist==1.6.2 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 # via asktable + # via httpx-aiohttp # via respx +httpx-aiohttp==0.1.6 + # via asktable idna==3.4 # via anyio # via httpx + # via yarl importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest @@ -51,6 +69,9 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py +multidict==6.4.4 + # via aiohttp + # via yarl mypy==1.14.1 mypy-extensions==1.0.0 # via mypy @@ -65,6 +86,9 @@ platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 # via pytest +propcache==0.3.1 + # via aiohttp + # via yarl pydantic==2.10.3 # via asktable pydantic-core==2.27.1 @@ -98,11 +122,14 @@ tomli==2.0.2 typing-extensions==4.12.2 # via anyio # via asktable + # via multidict # via mypy # via pydantic # via pydantic-core # via pyright virtualenv==20.24.5 # via nox +yarl==1.20.0 + # via aiohttp zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index fe5769b4..e94872e5 100644 --- a/requirements.lock +++ b/requirements.lock @@ -10,11 +10,22 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via asktable + # via httpx-aiohttp +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.4.0 # via asktable # via httpx +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -22,15 +33,28 @@ distro==1.8.0 # via asktable exceptiongroup==1.2.2 # via anyio +frozenlist==1.6.2 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 # via asktable + # via httpx-aiohttp +httpx-aiohttp==0.1.6 + # via asktable idna==3.4 # via anyio # via httpx + # via yarl +multidict==6.4.4 + # via aiohttp + # via yarl +propcache==0.3.1 + # via aiohttp + # via yarl pydantic==2.10.3 # via asktable pydantic-core==2.27.1 @@ -41,5 +65,8 @@ sniffio==1.3.0 typing-extensions==4.12.2 # via anyio # via asktable + # via multidict # via pydantic # via pydantic-core +yarl==1.20.0 + # via aiohttp diff --git a/src/asktable/__init__.py b/src/asktable/__init__.py index 76486c01..03765db6 100644 --- a/src/asktable/__init__.py +++ b/src/asktable/__init__.py @@ -36,7 +36,7 @@ UnprocessableEntityError, APIResponseValidationError, ) -from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging __all__ = [ @@ -78,6 +78,7 @@ "DEFAULT_CONNECTION_LIMITS", "DefaultHttpxClient", "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", ] if not _t.TYPE_CHECKING: diff --git a/src/asktable/_base_client.py b/src/asktable/_base_client.py index 8d24ebe9..6f0c23ca 100644 --- a/src/asktable/_base_client.py +++ b/src/asktable/_base_client.py @@ -1289,6 +1289,24 @@ def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + if TYPE_CHECKING: DefaultAsyncHttpxClient = httpx.AsyncClient """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK @@ -1297,8 +1315,12 @@ def __init__(self, **kwargs: Any) -> None: This is useful because overriding the `http_client` with your own instance of `httpx.AsyncClient` will result in httpx's defaults being used, not ours. """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" else: DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): diff --git a/tests/api_resources/chats/test_messages.py b/tests/api_resources/chats/test_messages.py index 59f3bc8b..93280c1b 100644 --- a/tests/api_resources/chats/test_messages.py +++ b/tests/api_resources/chats/test_messages.py @@ -161,7 +161,9 @@ def test_path_params_list(self, client: Asktable) -> None: class TestAsyncMessages: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/datasources/test_indexes.py b/tests/api_resources/datasources/test_indexes.py index 338264f7..e5aef3de 100644 --- a/tests/api_resources/datasources/test_indexes.py +++ b/tests/api_resources/datasources/test_indexes.py @@ -176,7 +176,9 @@ def test_path_params_delete(self, client: Asktable) -> None: class TestAsyncIndexes: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/datasources/test_meta.py b/tests/api_resources/datasources/test_meta.py index 91a71800..ae7a8f6e 100644 --- a/tests/api_resources/datasources/test_meta.py +++ b/tests/api_resources/datasources/test_meta.py @@ -246,7 +246,9 @@ def test_path_params_annotate(self, client: Asktable) -> None: class TestAsyncMeta: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/datasources/test_upload_params.py b/tests/api_resources/datasources/test_upload_params.py index f2e8d848..cb22379f 100644 --- a/tests/api_resources/datasources/test_upload_params.py +++ b/tests/api_resources/datasources/test_upload_params.py @@ -51,7 +51,9 @@ def test_streaming_response_create(self, client: Asktable) -> None: class TestAsyncUploadParams: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/extapis/test_routes.py b/tests/api_resources/extapis/test_routes.py index 65ed8f4a..aae62f3f 100644 --- a/tests/api_resources/extapis/test_routes.py +++ b/tests/api_resources/extapis/test_routes.py @@ -304,7 +304,9 @@ def test_path_params_delete(self, client: Asktable) -> None: class TestAsyncRoutes: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/sys/projects/test_api_keys.py b/tests/api_resources/sys/projects/test_api_keys.py index 9a7325f0..51966f80 100644 --- a/tests/api_resources/sys/projects/test_api_keys.py +++ b/tests/api_resources/sys/projects/test_api_keys.py @@ -202,7 +202,9 @@ def test_path_params_create_token(self, client: Asktable) -> None: class TestAsyncAPIKeys: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/sys/test_projects.py b/tests/api_resources/sys/test_projects.py index 97e7ebc8..274bc826 100644 --- a/tests/api_resources/sys/test_projects.py +++ b/tests/api_resources/sys/test_projects.py @@ -237,7 +237,9 @@ def test_streaming_response_model_groups(self, client: Asktable) -> None: class TestAsyncProjects: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_answers.py b/tests/api_resources/test_answers.py index c9c94653..dc2260f5 100644 --- a/tests/api_resources/test_answers.py +++ b/tests/api_resources/test_answers.py @@ -100,7 +100,9 @@ def test_streaming_response_list(self, client: Asktable) -> None: class TestAsyncAnswers: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_auth.py b/tests/api_resources/test_auth.py index 18a08f28..e08b155e 100644 --- a/tests/api_resources/test_auth.py +++ b/tests/api_resources/test_auth.py @@ -82,7 +82,9 @@ def test_streaming_response_me(self, client: Asktable) -> None: class TestAsyncAuth: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @parametrize async def test_method_create_token(self, async_client: AsyncAsktable) -> None: diff --git a/tests/api_resources/test_bots.py b/tests/api_resources/test_bots.py index 015f76df..09b2a320 100644 --- a/tests/api_resources/test_bots.py +++ b/tests/api_resources/test_bots.py @@ -301,7 +301,9 @@ def test_path_params_invite(self, client: Asktable) -> None: class TestAsyncBots: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_business_glossary.py b/tests/api_resources/test_business_glossary.py index 744c497e..5016bd69 100644 --- a/tests/api_resources/test_business_glossary.py +++ b/tests/api_resources/test_business_glossary.py @@ -230,7 +230,9 @@ def test_path_params_delete(self, client: Asktable) -> None: class TestAsyncBusinessGlossary: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_caches.py b/tests/api_resources/test_caches.py index 29b2de80..637c192e 100644 --- a/tests/api_resources/test_caches.py +++ b/tests/api_resources/test_caches.py @@ -55,7 +55,9 @@ def test_path_params_delete(self, client: Asktable) -> None: class TestAsyncCaches: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_chats.py b/tests/api_resources/test_chats.py index 254fc7c6..9748cf24 100644 --- a/tests/api_resources/test_chats.py +++ b/tests/api_resources/test_chats.py @@ -169,7 +169,9 @@ def test_path_params_delete(self, client: Asktable) -> None: class TestAsyncChats: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_dataframes.py b/tests/api_resources/test_dataframes.py index 8e71063a..97213e15 100644 --- a/tests/api_resources/test_dataframes.py +++ b/tests/api_resources/test_dataframes.py @@ -57,7 +57,9 @@ def test_path_params_retrieve(self, client: Asktable) -> None: class TestAsyncDataframes: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_datasources.py b/tests/api_resources/test_datasources.py index 758b1d57..ba4d2ab1 100644 --- a/tests/api_resources/test_datasources.py +++ b/tests/api_resources/test_datasources.py @@ -437,7 +437,9 @@ def test_path_params_update_field(self, client: Asktable) -> None: class TestAsyncDatasources: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_extapis.py b/tests/api_resources/test_extapis.py index 0e7bdaab..ec717cf0 100644 --- a/tests/api_resources/test_extapis.py +++ b/tests/api_resources/test_extapis.py @@ -221,7 +221,9 @@ def test_path_params_delete(self, client: Asktable) -> None: class TestAsyncExtapis: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index 6b979645..182300f2 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -56,7 +56,9 @@ def test_path_params_retrieve(self, client: Asktable) -> None: class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_integration.py b/tests/api_resources/test_integration.py index 213f98ae..47336152 100644 --- a/tests/api_resources/test_integration.py +++ b/tests/api_resources/test_integration.py @@ -104,7 +104,9 @@ def test_streaming_response_excel_csv_ask(self, client: Asktable) -> None: class TestAsyncIntegration: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "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: diff --git a/tests/api_resources/test_policies.py b/tests/api_resources/test_policies.py index 0323ef89..b7c78fa4 100644 --- a/tests/api_resources/test_policies.py +++ b/tests/api_resources/test_policies.py @@ -294,7 +294,9 @@ def test_path_params_delete(self, client: Asktable) -> None: class TestAsyncPolicies: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_polish.py b/tests/api_resources/test_polish.py index 45ff3b66..0a00baf2 100644 --- a/tests/api_resources/test_polish.py +++ b/tests/api_resources/test_polish.py @@ -62,7 +62,9 @@ def test_streaming_response_create(self, client: Asktable) -> None: class TestAsyncPolish: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_preferences.py b/tests/api_resources/test_preferences.py index 467d7894..06808683 100644 --- a/tests/api_resources/test_preferences.py +++ b/tests/api_resources/test_preferences.py @@ -145,7 +145,9 @@ def test_streaming_response_delete(self, client: Asktable) -> None: class TestAsyncPreferences: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_project.py b/tests/api_resources/test_project.py index 0ce1485d..e22563d8 100644 --- a/tests/api_resources/test_project.py +++ b/tests/api_resources/test_project.py @@ -103,7 +103,9 @@ def test_streaming_response_list_model_groups(self, client: Asktable) -> None: class TestAsyncProject: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_roles.py b/tests/api_resources/test_roles.py index 37f39920..b14375ad 100644 --- a/tests/api_resources/test_roles.py +++ b/tests/api_resources/test_roles.py @@ -305,7 +305,9 @@ def test_path_params_get_variables(self, client: Asktable) -> None: class TestAsyncRoles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_scores.py b/tests/api_resources/test_scores.py index 36f7bb8e..c6fcbe86 100644 --- a/tests/api_resources/test_scores.py +++ b/tests/api_resources/test_scores.py @@ -56,7 +56,9 @@ def test_streaming_response_create(self, client: Asktable) -> None: class TestAsyncScores: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_securetunnels.py b/tests/api_resources/test_securetunnels.py index 6b2602a7..8ab246ed 100644 --- a/tests/api_resources/test_securetunnels.py +++ b/tests/api_resources/test_securetunnels.py @@ -258,7 +258,9 @@ def test_path_params_list_links(self, client: Asktable) -> None: class TestAsyncSecuretunnels: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_sqls.py b/tests/api_resources/test_sqls.py index 258ae9a0..b1f756dc 100644 --- a/tests/api_resources/test_sqls.py +++ b/tests/api_resources/test_sqls.py @@ -99,7 +99,9 @@ def test_streaming_response_list(self, client: Asktable) -> None: class TestAsyncSqls: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/api_resources/test_trainings.py b/tests/api_resources/test_trainings.py index c25076c6..c3f065e4 100644 --- a/tests/api_resources/test_trainings.py +++ b/tests/api_resources/test_trainings.py @@ -154,7 +154,9 @@ def test_path_params_delete(self, client: Asktable) -> None: class TestAsyncTrainings: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + 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: diff --git a/tests/conftest.py b/tests/conftest.py index 7d29f540..1a093720 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,10 +6,12 @@ import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator +import httpx import pytest from pytest_asyncio import is_async_test -from asktable import Asktable, AsyncAsktable +from asktable import Asktable, AsyncAsktable, DefaultAioHttpClient +from asktable._utils import is_dict if TYPE_CHECKING: from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] @@ -27,6 +29,19 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: for async_test in pytest_asyncio_tests: async_test.add_marker(session_scope_marker, append=False) + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + async_client_param = item.callspec.params.get("async_client") + if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": + item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -45,9 +60,25 @@ def client(request: FixtureRequest) -> Iterator[Asktable]: @pytest.fixture(scope="session") async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncAsktable]: - strict = getattr(request, "param", True) - if not isinstance(strict, bool): - raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") - - async with AsyncAsktable(base_url=base_url, api_key=api_key, _strict_response_validation=strict) as client: + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") + + async with AsyncAsktable( + base_url=base_url, api_key=api_key, _strict_response_validation=strict, http_client=http_client + ) as client: yield client From 188abef74adcaf1c5b8b4ee8b39315aba98c7f95 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:20:02 +0000 Subject: [PATCH 21/35] chore(tests): skip some failing tests on the latest python versions --- tests/test_client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index a8031ab6..94cc3638 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -191,6 +191,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) 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: options = FinalRequestOptions(method="get", url="/foo") @@ -985,6 +986,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) 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: options = FinalRequestOptions(method="get", url="/foo") From 71f15b7d055dafd7aabb993d5ca0f6ca33707620 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 02:37:21 +0000 Subject: [PATCH 22/35] =?UTF-8?q?fix(ci):=20release-doctor=20=E2=80=94=20r?= =?UTF-8?q?eport=20correct=20token=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/check-release-environment | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/check-release-environment b/bin/check-release-environment index b8200669..b845b0f4 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -3,7 +3,7 @@ errors=() if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The ASKTABLE_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") + errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") fi lenErrors=${#errors[@]} From f5756ca55464cba7219498f0fcf0786d299fdc7d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 08:35:01 +0000 Subject: [PATCH 23/35] chore(ci): only run for pushes and fork pull requests --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a69511ac..b0f4c63d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ 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 steps: - uses: actions/checkout@v4 @@ -42,6 +43,7 @@ jobs: contents: read id-token: write runs-on: depot-ubuntu-24.04 + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -62,6 +64,7 @@ jobs: timeout-minutes: 10 name: test 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 From b23a0530daffe5b27939e7ab9516790f6fb36a7b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 02:32:23 +0000 Subject: [PATCH 24/35] fix(ci): correct conditional --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0f4c63d..e09e16b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,14 +36,13 @@ jobs: run: ./scripts/lint upload: - if: github.repository == 'stainless-sdks/asktable-python' + if: github.repository == 'stainless-sdks/asktable-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 name: upload permissions: contents: read id-token: write runs-on: depot-ubuntu-24.04 - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 From bef0279619acc20ff8f365f951c5469962529b4a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 06:21:58 +0000 Subject: [PATCH 25/35] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f3c7e7e0..481feae7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 96 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-66763c323b003a16c4b3adc5cc14d1f4e4b02ccddc3c2dbbebff70ae6a90f753.yml -openapi_spec_hash: 048225c24d300aab5562eb916c4172b8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-420512609e3f9f33f8a5b2d0086d4d3152b78935f1dc689cf4c5adf245241ba8.yml +openapi_spec_hash: a0055c3c329900b7a66dc27f4bea86cb config_hash: a572ab842ea60ce13f1d1a1358440cbe From 267f707806319c9b4499046f286f891a985d22de Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 05:21:42 +0000 Subject: [PATCH 26/35] chore(ci): change upload type --- .github/workflows/ci.yml | 18 ++++++++++++++++-- scripts/utils/upload-artifact.sh | 12 +++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e09e16b3..8ccc7f01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,10 +35,10 @@ jobs: - name: Run lints run: ./scripts/lint - upload: + build: if: github.repository == 'stainless-sdks/asktable-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 - name: upload + name: build permissions: contents: read id-token: write @@ -46,6 +46,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run build + run: rye build + - name: Get GitHub OIDC Token id: github-oidc uses: actions/github-script@v6 diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 2acefac1..b7b22e74 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash set -exuo pipefail -RESPONSE=$(curl -X POST "$URL" \ +FILENAME=$(basename dist/*.whl) + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ -H "Authorization: Bearer $AUTH" \ -H "Content-Type: application/json") @@ -12,13 +14,13 @@ if [[ "$SIGNED_URL" == "null" ]]; then exit 1 fi -UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ - -H "Content-Type: application/gzip" \ - --data-binary @- "$SIGNED_URL" 2>&1) +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: binary/octet-stream" \ + --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/asktable-python/$SHA'\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/asktable-python/$SHA/$FILENAME'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 From c28194157b0e93b082fc5c441528a4bdc0640c00 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:16:40 +0000 Subject: [PATCH 27/35] chore(internal): codegen related update --- requirements-dev.lock | 2 +- requirements.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 8628ca16..8da4896e 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -56,7 +56,7 @@ httpx==0.28.1 # via asktable # via httpx-aiohttp # via respx -httpx-aiohttp==0.1.6 +httpx-aiohttp==0.1.8 # via asktable idna==3.4 # via anyio diff --git a/requirements.lock b/requirements.lock index e94872e5..c3a1e6e7 100644 --- a/requirements.lock +++ b/requirements.lock @@ -43,7 +43,7 @@ httpcore==1.0.2 httpx==0.28.1 # via asktable # via httpx-aiohttp -httpx-aiohttp==0.1.6 +httpx-aiohttp==0.1.8 # via asktable idna==3.4 # via anyio From cb545771166f525600c876d70e6ca9af74aada7f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 02:33:43 +0000 Subject: [PATCH 28/35] chore(internal): bump pinned h11 dep --- requirements-dev.lock | 4 ++-- requirements.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 8da4896e..9701ab71 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -48,9 +48,9 @@ filelock==3.12.4 frozenlist==1.6.2 # via aiohttp # via aiosignal -h11==0.14.0 +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx httpx==0.28.1 # via asktable diff --git a/requirements.lock b/requirements.lock index c3a1e6e7..ac6e943f 100644 --- a/requirements.lock +++ b/requirements.lock @@ -36,9 +36,9 @@ exceptiongroup==1.2.2 frozenlist==1.6.2 # via aiohttp # via aiosignal -h11==0.14.0 +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx httpx==0.28.1 # via asktable From e1a20f7a5f7ce9dee0d182c2addc5fcf8b4342ae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 02:53:40 +0000 Subject: [PATCH 29/35] chore(package): mark python 3.13 as supported --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index bffcba11..cbe2a074 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", From 5fcaeb76ff37258c12becb7e459a3cfa56988fc0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 02:48:10 +0000 Subject: [PATCH 30/35] fix(parsing): correctly handle nested discriminated unions --- src/asktable/_models.py | 13 +++++++----- tests/test_models.py | 45 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/asktable/_models.py b/src/asktable/_models.py index 4f214980..528d5680 100644 --- a/src/asktable/_models.py +++ b/src/asktable/_models.py @@ -2,9 +2,10 @@ import os import inspect -from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast +from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( + List, Unpack, Literal, ClassVar, @@ -366,7 +367,7 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") - return construct_type(value=value, type_=type_) + return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) def is_basemodel(type_: type) -> bool: @@ -420,7 +421,7 @@ def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: return cast(_T, construct_type(value=value, type_=type_)) -def construct_type(*, value: object, type_: object) -> object: +def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: """Loose coercion to the expected type with construction of nested values. If the given value does not match the expected type then it is returned as-is. @@ -438,8 +439,10 @@ def construct_type(*, value: object, type_: object) -> object: type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(type_): - meta: tuple[Any, ...] = get_args(type_)[1:] + if metadata is not None: + meta: tuple[Any, ...] = tuple(metadata) + elif is_annotated_type(type_): + meta = get_args(type_)[1:] type_ = extract_type_arg(type_, 0) else: meta = tuple() diff --git a/tests/test_models.py b/tests/test_models.py index 8184554c..7864490f 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -889,3 +889,48 @@ class ModelB(BaseModel): ) assert isinstance(m, ModelB) + + +def test_nested_discriminated_union() -> None: + class InnerType1(BaseModel): + type: Literal["type_1"] + + class InnerModel(BaseModel): + inner_value: str + + class InnerType2(BaseModel): + type: Literal["type_2"] + some_inner_model: InnerModel + + class Type1(BaseModel): + base_type: Literal["base_type_1"] + value: Annotated[ + Union[ + InnerType1, + InnerType2, + ], + PropertyInfo(discriminator="type"), + ] + + class Type2(BaseModel): + base_type: Literal["base_type_2"] + + T = Annotated[ + Union[ + Type1, + Type2, + ], + PropertyInfo(discriminator="base_type"), + ] + + model = construct_type( + type_=T, + value={ + "base_type": "base_type_1", + "value": { + "type": "type_2", + }, + }, + ) + assert isinstance(model, Type1) + assert isinstance(model.value, InnerType2) From e05e6e562cfddd5ef7b3ee27a2a155e0e8305e6c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 03:20:04 +0000 Subject: [PATCH 31/35] chore(readme): fix version rendering on pypi --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c5deedae..dfe8bbb9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Asktable Python API library -[![PyPI version]()](https://pypi.org/project/asktable/) + +[![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+ application. The library includes type definitions for all request params and response fields, From 41feabcb23fb5c257d18ba7f96f0ddb9304d53d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 12 Jul 2025 02:13:23 +0000 Subject: [PATCH 32/35] fix(client): don't send Content-Type header on GET requests --- pyproject.toml | 2 +- src/asktable/_base_client.py | 11 +++++++++-- tests/test_client.py | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cbe2a074..35db05e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ Homepage = "https://github.com/DataMini/asktable-python" Repository = "https://github.com/DataMini/asktable-python" [project.optional-dependencies] -aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] [tool.rye] managed = true diff --git a/src/asktable/_base_client.py b/src/asktable/_base_client.py index 6f0c23ca..4678a3ee 100644 --- a/src/asktable/_base_client.py +++ b/src/asktable/_base_client.py @@ -529,6 +529,15 @@ def _build_request( # work around https://github.com/encode/httpx/discussions/2880 kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + is_body_allowed = options.method.lower() != "get" + + if is_body_allowed: + kwargs["json"] = json_data if is_given(json_data) else None + kwargs["files"] = files + else: + headers.pop("Content-Type", None) + kwargs.pop("data", None) + # TODO: report this error to httpx return self._client.build_request( # pyright: ignore[reportUnknownMemberType] headers=headers, @@ -540,8 +549,6 @@ def _build_request( # so that passing a `TypedDict` doesn't cause an error. # https://github.com/microsoft/pyright/issues/3526#event-6715453066 params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - json=json_data if is_given(json_data) else None, - files=files, **kwargs, ) diff --git a/tests/test_client.py b/tests/test_client.py index 94cc3638..76c130aa 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -454,7 +454,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, client: Asktable) -> None: request = client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, @@ -1249,7 +1249,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, async_client: AsyncAsktable) -> None: request = async_client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, From 6002d277b7004e7fdd69f8b23572cf84a6cf10da Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 02:12:52 +0000 Subject: [PATCH 33/35] feat: clean up environment call outs --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index dfe8bbb9..cab856b6 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,6 @@ 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 @@ -91,7 +90,7 @@ from asktable import AsyncAsktable async def main() -> None: async with AsyncAsktable( - api_key=os.environ.get("ASKTABLE_API_KEY"), # This is the default and can be omitted + api_key="My API Key", http_client=DefaultAioHttpClient(), ) as client: datasource = await client.datasources.create( From cf653ef0d527894151c209f7eb79b120e8d7109c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 19 Jul 2025 04:26:39 +0000 Subject: [PATCH 34/35] feat(api): add test set api --- .stats.yml | 4 +- api.md | 125 +++- src/asktable/_client.py | 27 +- src/asktable/resources/__init__.py | 42 +- src/asktable/resources/ats/__init__.py | 47 ++ .../{extapis/extapis.py => ats/ats.py} | 381 +++++------ src/asktable/resources/ats/task.py | 509 +++++++++++++++ .../{extapis/routes.py => ats/test_case.py} | 491 +++++++-------- src/asktable/resources/extapis/__init__.py | 33 - .../resources/sys/projects/projects.py | 156 ++++- src/asktable/resources/sys/sys.py | 103 +++ src/asktable/resources/trainings.py | 141 ++++- src/asktable/resources/user/__init__.py | 33 + src/asktable/resources/user/projects.py | 288 +++++++++ src/asktable/resources/user/user.py | 102 +++ src/asktable/types/__init__.py | 16 +- src/asktable/types/ats/__init__.py | 18 + .../types/ats/task_get_case_tasks_params.py | 17 + .../types/ats/task_get_case_tasks_response.py | 73 +++ .../task_list_params.py} | 8 +- src/asktable/types/ats/task_list_response.py | 49 ++ .../types/ats/task_retrieve_response.py | 49 ++ src/asktable/types/ats/task_run_params.py | 16 + src/asktable/types/ats/task_run_response.py | 49 ++ .../types/ats/test_case_create_params.py | 22 + .../types/ats/test_case_create_response.py | 35 ++ .../types/ats/test_case_list_params.py | 15 + .../types/ats/test_case_list_response.py | 35 ++ .../types/ats/test_case_retrieve_response.py | 35 ++ .../types/ats/test_case_update_params.py | 24 + .../types/ats/test_case_update_response.py | 35 ++ src/asktable/types/ats_create_params.py | 15 + src/asktable/types/ats_create_response.py | 27 + src/asktable/types/ats_delete_params.py | 12 + src/asktable/types/ats_list_params.py | 18 + src/asktable/types/ats_list_response.py | 27 + src/asktable/types/ats_retrieve_response.py | 27 + src/asktable/types/ats_update_params.py | 12 + src/asktable/types/ats_update_response.py | 27 + src/asktable/types/extapi.py | 27 - src/asktable/types/extapi_create_params.py | 19 - src/asktable/types/extapi_update_params.py | 19 - src/asktable/types/extapis/__init__.py | 8 - src/asktable/types/extapis/extapi_route.py | 39 -- .../types/extapis/route_create_params.py | 41 -- .../types/extapis/route_list_response.py | 10 - .../types/extapis/route_update_params.py | 30 - src/asktable/types/sy_update_config_params.py | 13 + .../types/sy_update_config_response.py | 12 + src/asktable/types/sys/__init__.py | 1 + .../types/sys/project_import_params.py | 11 + src/asktable/types/training_update_params.py | 25 + .../types/training_update_response.py | 47 ++ src/asktable/types/user/__init__.py | 8 + .../project_retrieve_model_groups_response.py | 10 + .../user/project_update_my_project_params.py | 16 + .../{extapis => ats}/__init__.py | 0 tests/api_resources/ats/test_task.py | 428 +++++++++++++ tests/api_resources/ats/test_test_case.py | 570 +++++++++++++++++ tests/api_resources/extapis/test_routes.py | 593 ------------------ tests/api_resources/sys/test_projects.py | 138 ++++ .../{test_extapis.py => test_ats.py} | 325 +++++----- tests/api_resources/test_sys.py | 88 +++ tests/api_resources/test_trainings.py | 109 ++++ tests/api_resources/user/__init__.py | 1 + tests/api_resources/user/test_projects.py | 191 ++++++ 66 files changed, 4431 insertions(+), 1491 deletions(-) create mode 100644 src/asktable/resources/ats/__init__.py rename src/asktable/resources/{extapis/extapis.py => ats/ats.py} (64%) create mode 100644 src/asktable/resources/ats/task.py rename src/asktable/resources/{extapis/routes.py => ats/test_case.py} (53%) delete mode 100644 src/asktable/resources/extapis/__init__.py create mode 100644 src/asktable/resources/user/__init__.py create mode 100644 src/asktable/resources/user/projects.py create mode 100644 src/asktable/resources/user/user.py create mode 100644 src/asktable/types/ats/__init__.py create mode 100644 src/asktable/types/ats/task_get_case_tasks_params.py create mode 100644 src/asktable/types/ats/task_get_case_tasks_response.py rename src/asktable/types/{extapi_list_params.py => ats/task_list_params.py} (61%) create mode 100644 src/asktable/types/ats/task_list_response.py create mode 100644 src/asktable/types/ats/task_retrieve_response.py create mode 100644 src/asktable/types/ats/task_run_params.py create mode 100644 src/asktable/types/ats/task_run_response.py create mode 100644 src/asktable/types/ats/test_case_create_params.py create mode 100644 src/asktable/types/ats/test_case_create_response.py create mode 100644 src/asktable/types/ats/test_case_list_params.py create mode 100644 src/asktable/types/ats/test_case_list_response.py create mode 100644 src/asktable/types/ats/test_case_retrieve_response.py create mode 100644 src/asktable/types/ats/test_case_update_params.py create mode 100644 src/asktable/types/ats/test_case_update_response.py create mode 100644 src/asktable/types/ats_create_params.py create mode 100644 src/asktable/types/ats_create_response.py create mode 100644 src/asktable/types/ats_delete_params.py create mode 100644 src/asktable/types/ats_list_params.py create mode 100644 src/asktable/types/ats_list_response.py create mode 100644 src/asktable/types/ats_retrieve_response.py create mode 100644 src/asktable/types/ats_update_params.py create mode 100644 src/asktable/types/ats_update_response.py delete mode 100644 src/asktable/types/extapi.py delete mode 100644 src/asktable/types/extapi_create_params.py delete mode 100644 src/asktable/types/extapi_update_params.py delete mode 100644 src/asktable/types/extapis/__init__.py delete mode 100644 src/asktable/types/extapis/extapi_route.py delete mode 100644 src/asktable/types/extapis/route_create_params.py delete mode 100644 src/asktable/types/extapis/route_list_response.py delete mode 100644 src/asktable/types/extapis/route_update_params.py create mode 100644 src/asktable/types/sy_update_config_params.py create mode 100644 src/asktable/types/sy_update_config_response.py create mode 100644 src/asktable/types/sys/project_import_params.py create mode 100644 src/asktable/types/training_update_params.py create mode 100644 src/asktable/types/training_update_response.py create mode 100644 src/asktable/types/user/__init__.py create mode 100644 src/asktable/types/user/project_retrieve_model_groups_response.py create mode 100644 src/asktable/types/user/project_update_my_project_params.py rename tests/api_resources/{extapis => ats}/__init__.py (100%) create mode 100644 tests/api_resources/ats/test_task.py create mode 100644 tests/api_resources/ats/test_test_case.py delete mode 100644 tests/api_resources/extapis/test_routes.py rename tests/api_resources/{test_extapis.py => test_ats.py} (52%) create mode 100644 tests/api_resources/test_sys.py create mode 100644 tests/api_resources/user/__init__.py create mode 100644 tests/api_resources/user/test_projects.py diff --git a/.stats.yml b/.stats.yml index 481feae7..b3408abe 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 96 +configured_endpoints: 107 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/datamini%2Fasktable-420512609e3f9f33f8a5b2d0086d4d3152b78935f1dc689cf4c5adf245241ba8.yml openapi_spec_hash: a0055c3c329900b7a66dc27f4bea86cb -config_hash: a572ab842ea60ce13f1d1a1358440cbe +config_hash: acdf4142177ed1932c2d82372693f811 diff --git a/api.md b/api.md index eca8c2e3..4d02c1ed 100644 --- a/api.md +++ b/api.md @@ -6,6 +6,16 @@ from asktable.types import Policy # Sys +Types: + +```python +from asktable.types import SyUpdateConfigResponse +``` + +Methods: + +- client.sys.update_config(\*\*params) -> SyUpdateConfigResponse + ## Projects Types: @@ -21,6 +31,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.model_groups() -> ProjectModelGroupsResponse ### APIKeys @@ -178,38 +190,6 @@ Methods: - client.bots.delete(bot_id) -> object - client.bots.invite(bot_id, \*\*params) -> object -# Extapis - -Types: - -```python -from asktable.types import Extapi -``` - -Methods: - -- client.extapis.create(\*\*params) -> Extapi -- client.extapis.retrieve(extapi_id) -> Extapi -- client.extapis.update(extapi_id, \*\*params) -> Extapi -- client.extapis.list(\*\*params) -> SyncPage[Extapi] -- client.extapis.delete(extapi_id) -> object - -## Routes - -Types: - -```python -from asktable.types.extapis import ExtapiRoute, RouteListResponse -``` - -Methods: - -- client.extapis.routes.create(path_extapi_id, \*\*params) -> ExtapiRoute -- client.extapis.routes.retrieve(route_id, \*, extapi_id) -> ExtapiRoute -- client.extapis.routes.update(route_id, \*, extapi_id, \*\*params) -> ExtapiRoute -- client.extapis.routes.list(extapi_id) -> RouteListResponse -- client.extapis.routes.delete(route_id, \*, extapi_id) -> None - # Auth Types: @@ -308,12 +288,13 @@ Methods: Types: ```python -from asktable.types import TrainingCreateResponse, TrainingListResponse +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 @@ -372,3 +353,81 @@ from asktable.types import PolishCreateResponse Methods: - client.polish.create(\*\*params) -> PolishCreateResponse + +# User + +## Projects + +Types: + +```python +from asktable.types.user import ProjectRetrieveModelGroupsResponse +``` + +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/src/asktable/_client.py b/src/asktable/_client.py index bd58763f..5c06a135 100644 --- a/src/asktable/_client.py +++ b/src/asktable/_client.py @@ -47,9 +47,10 @@ SyncAPIClient, AsyncAPIClient, ) +from .resources.ats import ats from .resources.sys import sys +from .resources.user import user from .resources.chats import chats -from .resources.extapis import extapis from .resources.datasources import datasources __all__ = [ @@ -72,7 +73,6 @@ class Asktable(SyncAPIClient): chats: chats.ChatsResource datasources: datasources.DatasourcesResource bots: bots.BotsResource - extapis: extapis.ExtapisResource auth: auth.AuthResource answers: answers.AnswersResource sqls: sqls.SqlsResource @@ -86,6 +86,8 @@ class Asktable(SyncAPIClient): files: files.FilesResource dataframes: dataframes.DataframesResource polish: polish.PolishResource + user: user.UserResource + ats: ats.ATSResource with_raw_response: AsktableWithRawResponse with_streaming_response: AsktableWithStreamedResponse @@ -150,7 +152,6 @@ def __init__( self.chats = chats.ChatsResource(self) self.datasources = datasources.DatasourcesResource(self) self.bots = bots.BotsResource(self) - self.extapis = extapis.ExtapisResource(self) self.auth = auth.AuthResource(self) self.answers = answers.AnswersResource(self) self.sqls = sqls.SqlsResource(self) @@ -164,6 +165,8 @@ def __init__( 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) @@ -280,7 +283,6 @@ class AsyncAsktable(AsyncAPIClient): chats: chats.AsyncChatsResource datasources: datasources.AsyncDatasourcesResource bots: bots.AsyncBotsResource - extapis: extapis.AsyncExtapisResource auth: auth.AsyncAuthResource answers: answers.AsyncAnswersResource sqls: sqls.AsyncSqlsResource @@ -294,6 +296,8 @@ class AsyncAsktable(AsyncAPIClient): files: files.AsyncFilesResource dataframes: dataframes.AsyncDataframesResource polish: polish.AsyncPolishResource + user: user.AsyncUserResource + ats: ats.AsyncATSResource with_raw_response: AsyncAsktableWithRawResponse with_streaming_response: AsyncAsktableWithStreamedResponse @@ -358,7 +362,6 @@ def __init__( self.chats = chats.AsyncChatsResource(self) self.datasources = datasources.AsyncDatasourcesResource(self) self.bots = bots.AsyncBotsResource(self) - self.extapis = extapis.AsyncExtapisResource(self) self.auth = auth.AsyncAuthResource(self) self.answers = answers.AsyncAnswersResource(self) self.sqls = sqls.AsyncSqlsResource(self) @@ -372,6 +375,8 @@ def __init__( 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) @@ -489,7 +494,6 @@ def __init__(self, client: Asktable) -> None: self.chats = chats.ChatsResourceWithRawResponse(client.chats) self.datasources = datasources.DatasourcesResourceWithRawResponse(client.datasources) self.bots = bots.BotsResourceWithRawResponse(client.bots) - self.extapis = extapis.ExtapisResourceWithRawResponse(client.extapis) self.auth = auth.AuthResourceWithRawResponse(client.auth) self.answers = answers.AnswersResourceWithRawResponse(client.answers) self.sqls = sqls.SqlsResourceWithRawResponse(client.sqls) @@ -503,6 +507,8 @@ def __init__(self, client: Asktable) -> None: 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) class AsyncAsktableWithRawResponse: @@ -514,7 +520,6 @@ def __init__(self, client: AsyncAsktable) -> None: self.chats = chats.AsyncChatsResourceWithRawResponse(client.chats) self.datasources = datasources.AsyncDatasourcesResourceWithRawResponse(client.datasources) self.bots = bots.AsyncBotsResourceWithRawResponse(client.bots) - self.extapis = extapis.AsyncExtapisResourceWithRawResponse(client.extapis) self.auth = auth.AsyncAuthResourceWithRawResponse(client.auth) self.answers = answers.AsyncAnswersResourceWithRawResponse(client.answers) self.sqls = sqls.AsyncSqlsResourceWithRawResponse(client.sqls) @@ -530,6 +535,8 @@ def __init__(self, client: AsyncAsktable) -> None: 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) class AsktableWithStreamedResponse: @@ -541,7 +548,6 @@ def __init__(self, client: Asktable) -> None: self.chats = chats.ChatsResourceWithStreamingResponse(client.chats) self.datasources = datasources.DatasourcesResourceWithStreamingResponse(client.datasources) self.bots = bots.BotsResourceWithStreamingResponse(client.bots) - self.extapis = extapis.ExtapisResourceWithStreamingResponse(client.extapis) self.auth = auth.AuthResourceWithStreamingResponse(client.auth) self.answers = answers.AnswersResourceWithStreamingResponse(client.answers) self.sqls = sqls.SqlsResourceWithStreamingResponse(client.sqls) @@ -557,6 +563,8 @@ def __init__(self, client: Asktable) -> None: 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) class AsyncAsktableWithStreamedResponse: @@ -568,7 +576,6 @@ def __init__(self, client: AsyncAsktable) -> None: self.chats = chats.AsyncChatsResourceWithStreamingResponse(client.chats) self.datasources = datasources.AsyncDatasourcesResourceWithStreamingResponse(client.datasources) self.bots = bots.AsyncBotsResourceWithStreamingResponse(client.bots) - self.extapis = extapis.AsyncExtapisResourceWithStreamingResponse(client.extapis) self.auth = auth.AsyncAuthResourceWithStreamingResponse(client.auth) self.answers = answers.AsyncAnswersResourceWithStreamingResponse(client.answers) self.sqls = sqls.AsyncSqlsResourceWithStreamingResponse(client.sqls) @@ -584,6 +591,8 @@ def __init__(self, client: AsyncAsktable) -> None: 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) Client = Asktable diff --git a/src/asktable/resources/__init__.py b/src/asktable/resources/__init__.py index 9f12d790..14a5d79a 100644 --- a/src/asktable/resources/__init__.py +++ b/src/asktable/resources/__init__.py @@ -1,5 +1,13 @@ # 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, @@ -32,6 +40,14 @@ SqlsResourceWithStreamingResponse, AsyncSqlsResourceWithStreamingResponse, ) +from .user import ( + UserResource, + AsyncUserResource, + UserResourceWithRawResponse, + AsyncUserResourceWithRawResponse, + UserResourceWithStreamingResponse, + AsyncUserResourceWithStreamingResponse, +) from .chats import ( ChatsResource, AsyncChatsResource, @@ -88,14 +104,6 @@ AnswersResourceWithStreamingResponse, AsyncAnswersResourceWithStreamingResponse, ) -from .extapis import ( - ExtapisResource, - AsyncExtapisResource, - ExtapisResourceWithRawResponse, - AsyncExtapisResourceWithRawResponse, - ExtapisResourceWithStreamingResponse, - AsyncExtapisResourceWithStreamingResponse, -) from .project import ( ProjectResource, AsyncProjectResource, @@ -212,12 +220,6 @@ "AsyncBotsResourceWithRawResponse", "BotsResourceWithStreamingResponse", "AsyncBotsResourceWithStreamingResponse", - "ExtapisResource", - "AsyncExtapisResource", - "ExtapisResourceWithRawResponse", - "AsyncExtapisResourceWithRawResponse", - "ExtapisResourceWithStreamingResponse", - "AsyncExtapisResourceWithStreamingResponse", "AuthResource", "AsyncAuthResource", "AuthResourceWithRawResponse", @@ -296,4 +298,16 @@ "AsyncPolishResourceWithRawResponse", "PolishResourceWithStreamingResponse", "AsyncPolishResourceWithStreamingResponse", + "UserResource", + "AsyncUserResource", + "UserResourceWithRawResponse", + "AsyncUserResourceWithRawResponse", + "UserResourceWithStreamingResponse", + "AsyncUserResourceWithStreamingResponse", + "ATSResource", + "AsyncATSResource", + "ATSResourceWithRawResponse", + "AsyncATSResourceWithRawResponse", + "ATSResourceWithStreamingResponse", + "AsyncATSResourceWithStreamingResponse", ] diff --git a/src/asktable/resources/ats/__init__.py b/src/asktable/resources/ats/__init__.py new file mode 100644 index 00000000..698c217d --- /dev/null +++ b/src/asktable/resources/ats/__init__.py @@ -0,0 +1,47 @@ +# 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/extapis/extapis.py b/src/asktable/resources/ats/ats.py similarity index 64% rename from src/asktable/resources/extapis/extapis.py rename to src/asktable/resources/ats/ats.py index 080c9361..64276c0d 100644 --- a/src/asktable/resources/extapis/extapis.py +++ b/src/asktable/resources/ats/ats.py @@ -2,22 +2,28 @@ from __future__ import annotations -from typing import Dict, Optional - import httpx -from .routes import ( - RoutesResource, - AsyncRoutesResource, - RoutesResourceWithRawResponse, - AsyncRoutesResourceWithRawResponse, - RoutesResourceWithStreamingResponse, - AsyncRoutesResourceWithStreamingResponse, +from .task import ( + TaskResource, + AsyncTaskResource, + TaskResourceWithRawResponse, + AsyncTaskResourceWithRawResponse, + TaskResourceWithStreamingResponse, + AsyncTaskResourceWithStreamingResponse, ) -from ...types import extapi_list_params, extapi_create_params, extapi_update_params +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, @@ -27,57 +33,61 @@ ) from ...pagination import SyncPage, AsyncPage from ..._base_client import AsyncPaginator, make_request_options -from ...types.extapi import Extapi +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"] -__all__ = ["ExtapisResource", "AsyncExtapisResource"] +class ATSResource(SyncAPIResource): + @cached_property + def test_case(self) -> TestCaseResource: + return TestCaseResource(self._client) -class ExtapisResource(SyncAPIResource): @cached_property - def routes(self) -> RoutesResource: - return RoutesResource(self._client) + def task(self) -> TaskResource: + return TaskResource(self._client) @cached_property - def with_raw_response(self) -> ExtapisResourceWithRawResponse: + 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 ExtapisResourceWithRawResponse(self) + return ATSResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> ExtapisResourceWithStreamingResponse: + 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 ExtapisResourceWithStreamingResponse(self) + return ATSResourceWithStreamingResponse(self) def create( self, *, - base_url: str, + datasource_id: str, name: str, - headers: Optional[Dict[str, 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, - ) -> Extapi: + ) -> ATSCreateResponse: """ - 创建一个新的 ExtAPI + Create Test Set Endpoint Args: - base_url: 根 URL - - name: 名称,不超过 64 个字符 + datasource_id: 该测试集对应数据源的 ID - headers: HTTP Headers,JSON 格式 + name: 测试集名称 extra_headers: Send extra headers @@ -88,24 +98,23 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ return self._post( - "/v1/extapis", + "/v1/ats", body=maybe_transform( { - "base_url": base_url, + "datasource_id": datasource_id, "name": name, - "headers": headers, }, - extapi_create_params.ExtapiCreateParams, + ats_create_params.ATSCreateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Extapi, + cast_to=ATSCreateResponse, ) def retrieve( self, - extapi_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. @@ -113,9 +122,9 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Extapi: + ) -> ATSRetrieveResponse: """ - 获取某个 ExtAPI + Get Test Set Endpoint Args: extra_headers: Send extra headers @@ -126,39 +135,33 @@ def retrieve( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") + 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/extapis/{extapi_id}", + 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=Extapi, + cast_to=ATSRetrieveResponse, ) def update( self, - extapi_id: str, + ats_id: str, *, - base_url: Optional[str] | NotGiven = NOT_GIVEN, - headers: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + 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, - ) -> Extapi: + ) -> ATSUpdateResponse: """ - 更新某个 ExtAPI + Update Test Set Endpoint Args: - base_url: 根 URL - - headers: HTTP Headers,JSON 格式 - - name: 名称,不超过 64 个字符 + name: 测试集更新的名字 extra_headers: Send extra headers @@ -168,28 +171,21 @@ def update( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - return self._post( - f"/v1/extapis/{extapi_id}", - body=maybe_transform( - { - "base_url": base_url, - "headers": headers, - "name": name, - }, - extapi_update_params.ExtapiUpdateParams, - ), + 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=Extapi, + cast_to=ATSUpdateResponse, ) def list( self, *, - name: Optional[str] | NotGiven = NOT_GIVEN, + 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. @@ -198,12 +194,12 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncPage[Extapi]: + ) -> SyncPage[ATSListResponse]: """ - 查询所有 ExtAPI + Get Test Sets Endpoint Args: - name: 名称 + datasource_id: 数据源 ID page: Page number @@ -218,8 +214,8 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ return self._get_api_list( - "/v1/extapis", - page=SyncPage[Extapi], + "/v1/ats", + page=SyncPage[ATSListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -227,20 +223,21 @@ def list( timeout=timeout, query=maybe_transform( { - "name": name, + "datasource_id": datasource_id, "page": page, "size": size, }, - extapi_list_params.ExtapiListParams, + ats_list_params.ATSListParams, ), ), - model=Extapi, + model=ATSListResponse, ) def delete( self, - extapi_id: str, + 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, @@ -249,9 +246,11 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> object: """ - 删除某个 ExtAPI + Delete Test Set Endpoint Args: + datasource_id: 数据源 ID + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -260,63 +259,68 @@ def delete( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") + 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/extapis/{extapi_id}", + f"/v1/ats/{ats_id}", options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + 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 AsyncExtapisResource(AsyncAPIResource): +class AsyncATSResource(AsyncAPIResource): @cached_property - def routes(self) -> AsyncRoutesResource: - return AsyncRoutesResource(self._client) + def test_case(self) -> AsyncTestCaseResource: + return AsyncTestCaseResource(self._client) @cached_property - def with_raw_response(self) -> AsyncExtapisResourceWithRawResponse: + 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 AsyncExtapisResourceWithRawResponse(self) + return AsyncATSResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AsyncExtapisResourceWithStreamingResponse: + 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 AsyncExtapisResourceWithStreamingResponse(self) + return AsyncATSResourceWithStreamingResponse(self) async def create( self, *, - base_url: str, + datasource_id: str, name: str, - headers: Optional[Dict[str, 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, - ) -> Extapi: + ) -> ATSCreateResponse: """ - 创建一个新的 ExtAPI + Create Test Set Endpoint Args: - base_url: 根 URL - - name: 名称,不超过 64 个字符 + datasource_id: 该测试集对应数据源的 ID - headers: HTTP Headers,JSON 格式 + name: 测试集名称 extra_headers: Send extra headers @@ -327,24 +331,23 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ return await self._post( - "/v1/extapis", + "/v1/ats", body=await async_maybe_transform( { - "base_url": base_url, + "datasource_id": datasource_id, "name": name, - "headers": headers, }, - extapi_create_params.ExtapiCreateParams, + ats_create_params.ATSCreateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Extapi, + cast_to=ATSCreateResponse, ) async def retrieve( self, - extapi_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. @@ -352,9 +355,9 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Extapi: + ) -> ATSRetrieveResponse: """ - 获取某个 ExtAPI + Get Test Set Endpoint Args: extra_headers: Send extra headers @@ -365,39 +368,33 @@ async def retrieve( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") + 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/extapis/{extapi_id}", + 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=Extapi, + cast_to=ATSRetrieveResponse, ) async def update( self, - extapi_id: str, + ats_id: str, *, - base_url: Optional[str] | NotGiven = NOT_GIVEN, - headers: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, + 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, - ) -> Extapi: + ) -> ATSUpdateResponse: """ - 更新某个 ExtAPI + Update Test Set Endpoint Args: - base_url: 根 URL - - headers: HTTP Headers,JSON 格式 - - name: 名称,不超过 64 个字符 + name: 测试集更新的名字 extra_headers: Send extra headers @@ -407,28 +404,21 @@ async def update( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - return await self._post( - f"/v1/extapis/{extapi_id}", - body=await async_maybe_transform( - { - "base_url": base_url, - "headers": headers, - "name": name, - }, - extapi_update_params.ExtapiUpdateParams, - ), + 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=Extapi, + cast_to=ATSUpdateResponse, ) def list( self, *, - name: Optional[str] | NotGiven = NOT_GIVEN, + 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. @@ -437,12 +427,12 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[Extapi, AsyncPage[Extapi]]: + ) -> AsyncPaginator[ATSListResponse, AsyncPage[ATSListResponse]]: """ - 查询所有 ExtAPI + Get Test Sets Endpoint Args: - name: 名称 + datasource_id: 数据源 ID page: Page number @@ -457,8 +447,8 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ return self._get_api_list( - "/v1/extapis", - page=AsyncPage[Extapi], + "/v1/ats", + page=AsyncPage[ATSListResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -466,20 +456,21 @@ def list( timeout=timeout, query=maybe_transform( { - "name": name, + "datasource_id": datasource_id, "page": page, "size": size, }, - extapi_list_params.ExtapiListParams, + ats_list_params.ATSListParams, ), ), - model=Extapi, + model=ATSListResponse, ) async def delete( self, - extapi_id: str, + 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, @@ -488,9 +479,11 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> object: """ - 删除某个 ExtAPI + Delete Test Set Endpoint Args: + datasource_id: 数据源 ID + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -499,112 +492,132 @@ async def delete( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") + 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/extapis/{extapi_id}", + f"/v1/ats/{ats_id}", options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + 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 ExtapisResourceWithRawResponse: - def __init__(self, extapis: ExtapisResource) -> None: - self._extapis = extapis +class ATSResourceWithRawResponse: + def __init__(self, ats: ATSResource) -> None: + self._ats = ats self.create = to_raw_response_wrapper( - extapis.create, + ats.create, ) self.retrieve = to_raw_response_wrapper( - extapis.retrieve, + ats.retrieve, ) self.update = to_raw_response_wrapper( - extapis.update, + ats.update, ) self.list = to_raw_response_wrapper( - extapis.list, + ats.list, ) self.delete = to_raw_response_wrapper( - extapis.delete, + ats.delete, ) @cached_property - def routes(self) -> RoutesResourceWithRawResponse: - return RoutesResourceWithRawResponse(self._extapis.routes) + def test_case(self) -> TestCaseResourceWithRawResponse: + return TestCaseResourceWithRawResponse(self._ats.test_case) + + @cached_property + def task(self) -> TaskResourceWithRawResponse: + return TaskResourceWithRawResponse(self._ats.task) -class AsyncExtapisResourceWithRawResponse: - def __init__(self, extapis: AsyncExtapisResource) -> None: - self._extapis = extapis +class AsyncATSResourceWithRawResponse: + def __init__(self, ats: AsyncATSResource) -> None: + self._ats = ats self.create = async_to_raw_response_wrapper( - extapis.create, + ats.create, ) self.retrieve = async_to_raw_response_wrapper( - extapis.retrieve, + ats.retrieve, ) self.update = async_to_raw_response_wrapper( - extapis.update, + ats.update, ) self.list = async_to_raw_response_wrapper( - extapis.list, + ats.list, ) self.delete = async_to_raw_response_wrapper( - extapis.delete, + ats.delete, ) @cached_property - def routes(self) -> AsyncRoutesResourceWithRawResponse: - return AsyncRoutesResourceWithRawResponse(self._extapis.routes) + def test_case(self) -> AsyncTestCaseResourceWithRawResponse: + return AsyncTestCaseResourceWithRawResponse(self._ats.test_case) + @cached_property + def task(self) -> AsyncTaskResourceWithRawResponse: + return AsyncTaskResourceWithRawResponse(self._ats.task) -class ExtapisResourceWithStreamingResponse: - def __init__(self, extapis: ExtapisResource) -> None: - self._extapis = extapis + +class ATSResourceWithStreamingResponse: + def __init__(self, ats: ATSResource) -> None: + self._ats = ats self.create = to_streamed_response_wrapper( - extapis.create, + ats.create, ) self.retrieve = to_streamed_response_wrapper( - extapis.retrieve, + ats.retrieve, ) self.update = to_streamed_response_wrapper( - extapis.update, + ats.update, ) self.list = to_streamed_response_wrapper( - extapis.list, + ats.list, ) self.delete = to_streamed_response_wrapper( - extapis.delete, + ats.delete, ) @cached_property - def routes(self) -> RoutesResourceWithStreamingResponse: - return RoutesResourceWithStreamingResponse(self._extapis.routes) + def test_case(self) -> TestCaseResourceWithStreamingResponse: + return TestCaseResourceWithStreamingResponse(self._ats.test_case) + + @cached_property + def task(self) -> TaskResourceWithStreamingResponse: + return TaskResourceWithStreamingResponse(self._ats.task) -class AsyncExtapisResourceWithStreamingResponse: - def __init__(self, extapis: AsyncExtapisResource) -> None: - self._extapis = extapis +class AsyncATSResourceWithStreamingResponse: + def __init__(self, ats: AsyncATSResource) -> None: + self._ats = ats self.create = async_to_streamed_response_wrapper( - extapis.create, + ats.create, ) self.retrieve = async_to_streamed_response_wrapper( - extapis.retrieve, + ats.retrieve, ) self.update = async_to_streamed_response_wrapper( - extapis.update, + ats.update, ) self.list = async_to_streamed_response_wrapper( - extapis.list, + ats.list, ) self.delete = async_to_streamed_response_wrapper( - extapis.delete, + ats.delete, ) @cached_property - def routes(self) -> AsyncRoutesResourceWithStreamingResponse: - return AsyncRoutesResourceWithStreamingResponse(self._extapis.routes) + 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 new file mode 100644 index 00000000..7950fed9 --- /dev/null +++ b/src/asktable/resources/ats/task.py @@ -0,0 +1,509 @@ +# 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/extapis/routes.py b/src/asktable/resources/ats/test_case.py similarity index 53% rename from src/asktable/resources/extapis/routes.py rename to src/asktable/resources/ats/test_case.py index 2f168725..58852a1a 100644 --- a/src/asktable/resources/extapis/routes.py +++ b/src/asktable/resources/ats/test_case.py @@ -2,13 +2,11 @@ from __future__ import annotations -from typing import Union, Optional -from datetime import datetime -from typing_extensions import Literal +from typing import Optional import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +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 @@ -18,71 +16,65 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ..._base_client import make_request_options -from ...types.extapis import route_create_params, route_update_params -from ...types.extapis.extapi_route import ExtapiRoute -from ...types.extapis.route_list_response import RouteListResponse +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__ = ["RoutesResource", "AsyncRoutesResource"] +__all__ = ["TestCaseResource", "AsyncTestCaseResource"] -class RoutesResource(SyncAPIResource): +class TestCaseResource(SyncAPIResource): + __test__ = False + @cached_property - def with_raw_response(self) -> RoutesResourceWithRawResponse: + 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 RoutesResourceWithRawResponse(self) + return TestCaseResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> RoutesResourceWithStreamingResponse: + 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 RoutesResourceWithStreamingResponse(self) + return TestCaseResourceWithStreamingResponse(self) def create( self, - path_extapi_id: str, + ats_id: str, *, - id: str, - created_at: Union[str, datetime], - body_extapi_id: str, - method: Literal["GET", "POST", "PUT", "DELETE"], - name: str, - path: str, - project_id: str, - updated_at: Union[str, datetime], - body_params_desc: Optional[str] | NotGiven = NOT_GIVEN, - path_params_desc: Optional[str] | NotGiven = NOT_GIVEN, - query_params_desc: Optional[str] | NotGiven = NOT_GIVEN, + 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, - ) -> ExtapiRoute: + ) -> TestCaseCreateResponse: """ - 为某个 ExtAPI 创建新的路径 + Create Test Case Endpoint Args: - method: HTTP 方法 - - name: API 方法名称,不超过 64 个字符 - - path: API 路径 + expected_sql: 用户期望生成的 sql - body_params_desc: 请求体参数描述 + question: 用户提问 - path_params_desc: 路径参数描述 + role_id: 角色 ID - query_params_desc: 查询参数描述 + role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 extra_headers: Send extra headers @@ -92,46 +84,39 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - if not path_extapi_id: - raise ValueError(f"Expected a non-empty value for `path_extapi_id` but received {path_extapi_id!r}") + 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/extapis/{path_extapi_id}/routes", + f"/v1/ats/{ats_id}/test-case", body=maybe_transform( { - "id": id, - "created_at": created_at, - "body_extapi_id": body_extapi_id, - "method": method, - "name": name, - "path": path, - "project_id": project_id, - "updated_at": updated_at, - "body_params_desc": body_params_desc, - "path_params_desc": path_params_desc, - "query_params_desc": query_params_desc, + "expected_sql": expected_sql, + "question": question, + "role_id": role_id, + "role_variables": role_variables, }, - route_create_params.RouteCreateParams, + 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=ExtapiRoute, + cast_to=TestCaseCreateResponse, ) def retrieve( self, - route_id: str, + atc_id: str, *, - extapi_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, - ) -> ExtapiRoute: + ) -> TestCaseRetrieveResponse: """ - 获取某个 ExtAPI Route + Get Test Case Endpoint Args: extra_headers: Send extra headers @@ -142,51 +127,45 @@ def retrieve( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - if not route_id: - raise ValueError(f"Expected a non-empty value for `route_id` but received {route_id!r}") + 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/extapis/{extapi_id}/routes/{route_id}", + 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=ExtapiRoute, + cast_to=TestCaseRetrieveResponse, ) def update( self, - route_id: str, + atc_id: str, *, - extapi_id: str, - body_params_desc: Optional[str] | NotGiven = NOT_GIVEN, - method: Optional[Literal["GET", "POST", "PUT", "DELETE"]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - path: Optional[str] | NotGiven = NOT_GIVEN, - path_params_desc: Optional[str] | NotGiven = NOT_GIVEN, - query_params_desc: Optional[str] | NotGiven = NOT_GIVEN, + 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, - ) -> ExtapiRoute: + ) -> TestCaseUpdateResponse: """ - 更新某个 ExtAPI Route + Update Test Case Endpoint Args: - body_params_desc: 请求体参数描述 + expected_sql: 用户期望生成的 sql - method: HTTP 方法 + question: 用户提问 - name: API 方法名称,不超过 64 个字符 + role_id: 角色 ID - path: API 路径 - - path_params_desc: 路径参数描述 - - query_params_desc: 查询参数描述 + role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 extra_headers: Send extra headers @@ -196,44 +175,48 @@ def update( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - if not route_id: - raise ValueError(f"Expected a non-empty value for `route_id` but received {route_id!r}") - return self._post( - f"/v1/extapis/{extapi_id}/routes/{route_id}", + 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( { - "body_params_desc": body_params_desc, - "method": method, - "name": name, - "path": path, - "path_params_desc": path_params_desc, - "query_params_desc": query_params_desc, + "expected_sql": expected_sql, + "question": question, + "role_id": role_id, + "role_variables": role_variables, }, - route_update_params.RouteUpdateParams, + 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=ExtapiRoute, + cast_to=TestCaseUpdateResponse, ) def list( self, - extapi_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, - ) -> RouteListResponse: + ) -> SyncPage[TestCaseListResponse]: """ - 获取某个 ExtAPI 的所有路径 + 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 @@ -242,30 +225,41 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - return self._get( - f"/v1/extapis/{extapi_id}/routes", + 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 + 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, + ), ), - cast_to=RouteListResponse, + model=TestCaseListResponse, ) def delete( self, - route_id: str, + atc_id: str, *, - extapi_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, - ) -> None: + ) -> object: """ - 删除某个 ExtAPI Route + Delete Test Case Endpoint Args: extra_headers: Send extra headers @@ -276,77 +270,65 @@ def delete( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - if not route_id: - raise ValueError(f"Expected a non-empty value for `route_id` but received {route_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} + 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/extapis/{extapi_id}/routes/{route_id}", + 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=NoneType, + cast_to=object, ) -class AsyncRoutesResource(AsyncAPIResource): +class AsyncTestCaseResource(AsyncAPIResource): @cached_property - def with_raw_response(self) -> AsyncRoutesResourceWithRawResponse: + 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 AsyncRoutesResourceWithRawResponse(self) + return AsyncTestCaseResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AsyncRoutesResourceWithStreamingResponse: + 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 AsyncRoutesResourceWithStreamingResponse(self) + return AsyncTestCaseResourceWithStreamingResponse(self) async def create( self, - path_extapi_id: str, + ats_id: str, *, - id: str, - created_at: Union[str, datetime], - body_extapi_id: str, - method: Literal["GET", "POST", "PUT", "DELETE"], - name: str, - path: str, - project_id: str, - updated_at: Union[str, datetime], - body_params_desc: Optional[str] | NotGiven = NOT_GIVEN, - path_params_desc: Optional[str] | NotGiven = NOT_GIVEN, - query_params_desc: Optional[str] | NotGiven = NOT_GIVEN, + 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, - ) -> ExtapiRoute: + ) -> TestCaseCreateResponse: """ - 为某个 ExtAPI 创建新的路径 + Create Test Case Endpoint Args: - method: HTTP 方法 - - name: API 方法名称,不超过 64 个字符 + expected_sql: 用户期望生成的 sql - path: API 路径 + question: 用户提问 - body_params_desc: 请求体参数描述 + role_id: 角色 ID - path_params_desc: 路径参数描述 - - query_params_desc: 查询参数描述 + role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 extra_headers: Send extra headers @@ -356,46 +338,39 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - if not path_extapi_id: - raise ValueError(f"Expected a non-empty value for `path_extapi_id` but received {path_extapi_id!r}") + 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/extapis/{path_extapi_id}/routes", + f"/v1/ats/{ats_id}/test-case", body=await async_maybe_transform( { - "id": id, - "created_at": created_at, - "body_extapi_id": body_extapi_id, - "method": method, - "name": name, - "path": path, - "project_id": project_id, - "updated_at": updated_at, - "body_params_desc": body_params_desc, - "path_params_desc": path_params_desc, - "query_params_desc": query_params_desc, + "expected_sql": expected_sql, + "question": question, + "role_id": role_id, + "role_variables": role_variables, }, - route_create_params.RouteCreateParams, + 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=ExtapiRoute, + cast_to=TestCaseCreateResponse, ) async def retrieve( self, - route_id: str, + atc_id: str, *, - extapi_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, - ) -> ExtapiRoute: + ) -> TestCaseRetrieveResponse: """ - 获取某个 ExtAPI Route + Get Test Case Endpoint Args: extra_headers: Send extra headers @@ -406,51 +381,45 @@ async def retrieve( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - if not route_id: - raise ValueError(f"Expected a non-empty value for `route_id` but received {route_id!r}") + 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/extapis/{extapi_id}/routes/{route_id}", + 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=ExtapiRoute, + cast_to=TestCaseRetrieveResponse, ) async def update( self, - route_id: str, + atc_id: str, *, - extapi_id: str, - body_params_desc: Optional[str] | NotGiven = NOT_GIVEN, - method: Optional[Literal["GET", "POST", "PUT", "DELETE"]] | NotGiven = NOT_GIVEN, - name: Optional[str] | NotGiven = NOT_GIVEN, - path: Optional[str] | NotGiven = NOT_GIVEN, - path_params_desc: Optional[str] | NotGiven = NOT_GIVEN, - query_params_desc: Optional[str] | NotGiven = NOT_GIVEN, + 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, - ) -> ExtapiRoute: + ) -> TestCaseUpdateResponse: """ - 更新某个 ExtAPI Route + Update Test Case Endpoint Args: - body_params_desc: 请求体参数描述 - - method: HTTP 方法 - - name: API 方法名称,不超过 64 个字符 + expected_sql: 用户期望生成的 sql - path: API 路径 + question: 用户提问 - path_params_desc: 路径参数描述 + role_id: 角色 ID - query_params_desc: 查询参数描述 + role_variables: 在扮演这个角色时需要传递的变量值,用 Key-Value 形式传递 extra_headers: Send extra headers @@ -460,44 +429,48 @@ async def update( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - if not route_id: - raise ValueError(f"Expected a non-empty value for `route_id` but received {route_id!r}") - return await self._post( - f"/v1/extapis/{extapi_id}/routes/{route_id}", + 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( { - "body_params_desc": body_params_desc, - "method": method, - "name": name, - "path": path, - "path_params_desc": path_params_desc, - "query_params_desc": query_params_desc, + "expected_sql": expected_sql, + "question": question, + "role_id": role_id, + "role_variables": role_variables, }, - route_update_params.RouteUpdateParams, + 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=ExtapiRoute, + cast_to=TestCaseUpdateResponse, ) - async def list( + def list( self, - extapi_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, - ) -> RouteListResponse: + ) -> AsyncPaginator[TestCaseListResponse, AsyncPage[TestCaseListResponse]]: """ - 获取某个 ExtAPI 的所有路径 + 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 @@ -506,30 +479,41 @@ async def list( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - return await self._get( - f"/v1/extapis/{extapi_id}/routes", + 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 + 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, + ), ), - cast_to=RouteListResponse, + model=TestCaseListResponse, ) async def delete( self, - route_id: str, + atc_id: str, *, - extapi_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, - ) -> None: + ) -> object: """ - 删除某个 ExtAPI Route + Delete Test Case Endpoint Args: extra_headers: Send extra headers @@ -540,99 +524,102 @@ async def delete( timeout: Override the client-level default timeout for this request, in seconds """ - if not extapi_id: - raise ValueError(f"Expected a non-empty value for `extapi_id` but received {extapi_id!r}") - if not route_id: - raise ValueError(f"Expected a non-empty value for `route_id` but received {route_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} + 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/extapis/{extapi_id}/routes/{route_id}", + 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=NoneType, + cast_to=object, ) -class RoutesResourceWithRawResponse: - def __init__(self, routes: RoutesResource) -> None: - self._routes = routes +class TestCaseResourceWithRawResponse: + __test__ = False + + def __init__(self, test_case: TestCaseResource) -> None: + self._test_case = test_case self.create = to_raw_response_wrapper( - routes.create, + test_case.create, ) self.retrieve = to_raw_response_wrapper( - routes.retrieve, + test_case.retrieve, ) self.update = to_raw_response_wrapper( - routes.update, + test_case.update, ) self.list = to_raw_response_wrapper( - routes.list, + test_case.list, ) self.delete = to_raw_response_wrapper( - routes.delete, + test_case.delete, ) -class AsyncRoutesResourceWithRawResponse: - def __init__(self, routes: AsyncRoutesResource) -> None: - self._routes = routes +class AsyncTestCaseResourceWithRawResponse: + def __init__(self, test_case: AsyncTestCaseResource) -> None: + self._test_case = test_case self.create = async_to_raw_response_wrapper( - routes.create, + test_case.create, ) self.retrieve = async_to_raw_response_wrapper( - routes.retrieve, + test_case.retrieve, ) self.update = async_to_raw_response_wrapper( - routes.update, + test_case.update, ) self.list = async_to_raw_response_wrapper( - routes.list, + test_case.list, ) self.delete = async_to_raw_response_wrapper( - routes.delete, + test_case.delete, ) -class RoutesResourceWithStreamingResponse: - def __init__(self, routes: RoutesResource) -> None: - self._routes = routes +class TestCaseResourceWithStreamingResponse: + __test__ = False + + def __init__(self, test_case: TestCaseResource) -> None: + self._test_case = test_case self.create = to_streamed_response_wrapper( - routes.create, + test_case.create, ) self.retrieve = to_streamed_response_wrapper( - routes.retrieve, + test_case.retrieve, ) self.update = to_streamed_response_wrapper( - routes.update, + test_case.update, ) self.list = to_streamed_response_wrapper( - routes.list, + test_case.list, ) self.delete = to_streamed_response_wrapper( - routes.delete, + test_case.delete, ) -class AsyncRoutesResourceWithStreamingResponse: - def __init__(self, routes: AsyncRoutesResource) -> None: - self._routes = routes +class AsyncTestCaseResourceWithStreamingResponse: + def __init__(self, test_case: AsyncTestCaseResource) -> None: + self._test_case = test_case self.create = async_to_streamed_response_wrapper( - routes.create, + test_case.create, ) self.retrieve = async_to_streamed_response_wrapper( - routes.retrieve, + test_case.retrieve, ) self.update = async_to_streamed_response_wrapper( - routes.update, + test_case.update, ) self.list = async_to_streamed_response_wrapper( - routes.list, + test_case.list, ) self.delete = async_to_streamed_response_wrapper( - routes.delete, + test_case.delete, ) diff --git a/src/asktable/resources/extapis/__init__.py b/src/asktable/resources/extapis/__init__.py deleted file mode 100644 index 1c2fb4bd..00000000 --- a/src/asktable/resources/extapis/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .routes import ( - RoutesResource, - AsyncRoutesResource, - RoutesResourceWithRawResponse, - AsyncRoutesResourceWithRawResponse, - RoutesResourceWithStreamingResponse, - AsyncRoutesResourceWithStreamingResponse, -) -from .extapis import ( - ExtapisResource, - AsyncExtapisResource, - ExtapisResourceWithRawResponse, - AsyncExtapisResourceWithRawResponse, - ExtapisResourceWithStreamingResponse, - AsyncExtapisResourceWithStreamingResponse, -) - -__all__ = [ - "RoutesResource", - "AsyncRoutesResource", - "RoutesResourceWithRawResponse", - "AsyncRoutesResourceWithRawResponse", - "RoutesResourceWithStreamingResponse", - "AsyncRoutesResourceWithStreamingResponse", - "ExtapisResource", - "AsyncExtapisResource", - "ExtapisResourceWithRawResponse", - "AsyncExtapisResourceWithRawResponse", - "ExtapisResourceWithStreamingResponse", - "AsyncExtapisResourceWithStreamingResponse", -] diff --git a/src/asktable/resources/sys/projects/projects.py b/src/asktable/resources/sys/projects/projects.py index eb8edeb3..6c7c5f13 100644 --- a/src/asktable/resources/sys/projects/projects.py +++ b/src/asktable/resources/sys/projects/projects.py @@ -24,7 +24,7 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ....types.sys import project_list_params, project_create_params, project_update_params +from ....types.sys import project_list_params, project_create_params, project_import_params, project_update_params from ....pagination import SyncPage, AsyncPage from ...._base_client import AsyncPaginator, make_request_options from ....types.sys.project import Project @@ -258,6 +258,71 @@ def delete( cast_to=object, ) + def export( + self, + 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: + """ + Export Project + + 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 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", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + def import_( + self, + *, + body: 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: + """ + Import Project + + 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/sys/projects/import", + body=maybe_transform(body, project_import_params.ProjectImportParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + def model_groups( self, *, @@ -503,6 +568,71 @@ async def delete( cast_to=object, ) + async def export( + self, + 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: + """ + Export Project + + 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 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", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + + async def import_( + self, + *, + body: 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: + """ + Import Project + + 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/sys/projects/import", + body=await async_maybe_transform(body, project_import_params.ProjectImportParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=object, + ) + async def model_groups( self, *, @@ -542,6 +672,12 @@ def __init__(self, projects: ProjectsResource) -> None: self.delete = to_raw_response_wrapper( projects.delete, ) + self.export = to_raw_response_wrapper( + projects.export, + ) + self.import_ = to_raw_response_wrapper( + projects.import_, + ) self.model_groups = to_raw_response_wrapper( projects.model_groups, ) @@ -570,6 +706,12 @@ def __init__(self, projects: AsyncProjectsResource) -> None: self.delete = async_to_raw_response_wrapper( projects.delete, ) + self.export = async_to_raw_response_wrapper( + projects.export, + ) + self.import_ = async_to_raw_response_wrapper( + projects.import_, + ) self.model_groups = async_to_raw_response_wrapper( projects.model_groups, ) @@ -598,6 +740,12 @@ def __init__(self, projects: ProjectsResource) -> None: self.delete = to_streamed_response_wrapper( projects.delete, ) + self.export = to_streamed_response_wrapper( + projects.export, + ) + self.import_ = to_streamed_response_wrapper( + projects.import_, + ) self.model_groups = to_streamed_response_wrapper( projects.model_groups, ) @@ -626,6 +774,12 @@ def __init__(self, projects: AsyncProjectsResource) -> None: self.delete = async_to_streamed_response_wrapper( projects.delete, ) + self.export = async_to_streamed_response_wrapper( + projects.export, + ) + self.import_ = async_to_streamed_response_wrapper( + projects.import_, + ) self.model_groups = async_to_streamed_response_wrapper( projects.model_groups, ) diff --git a/src/asktable/resources/sys/sys.py b/src/asktable/resources/sys/sys.py index 27f630db..3ab1213c 100644 --- a/src/asktable/resources/sys/sys.py +++ b/src/asktable/resources/sys/sys.py @@ -2,8 +2,22 @@ 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, @@ -12,6 +26,7 @@ ProjectsResourceWithStreamingResponse, AsyncProjectsResourceWithStreamingResponse, ) +from ...types.sy_update_config_response import SyUpdateConfigResponse __all__ = ["SysResource", "AsyncSysResource"] @@ -40,6 +55,42 @@ 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 @@ -65,11 +116,51 @@ 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) @@ -79,6 +170,10 @@ 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) @@ -88,6 +183,10 @@ 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) @@ -97,6 +196,10 @@ 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 index 6812639c..98882a5c 100644 --- a/src/asktable/resources/trainings.py +++ b/src/asktable/resources/trainings.py @@ -2,11 +2,11 @@ from __future__ import annotations -from typing import Iterable +from typing import Iterable, Optional import httpx -from ..types import training_list_params, training_create_params, training_delete_params +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 @@ -21,6 +21,7 @@ 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"] @@ -84,6 +85,67 @@ def create( 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, *, @@ -237,6 +299,69 @@ async def create( 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, *, @@ -338,6 +463,9 @@ def __init__(self, trainings: TrainingsResource) -> None: self.create = to_raw_response_wrapper( trainings.create, ) + self.update = to_raw_response_wrapper( + trainings.update, + ) self.list = to_raw_response_wrapper( trainings.list, ) @@ -353,6 +481,9 @@ def __init__(self, trainings: AsyncTrainingsResource) -> None: 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, ) @@ -368,6 +499,9 @@ def __init__(self, trainings: TrainingsResource) -> None: self.create = to_streamed_response_wrapper( trainings.create, ) + self.update = to_streamed_response_wrapper( + trainings.update, + ) self.list = to_streamed_response_wrapper( trainings.list, ) @@ -383,6 +517,9 @@ def __init__(self, trainings: AsyncTrainingsResource) -> None: 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, ) diff --git a/src/asktable/resources/user/__init__.py b/src/asktable/resources/user/__init__.py new file mode 100644 index 00000000..6a734a92 --- /dev/null +++ b/src/asktable/resources/user/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .user import ( + UserResource, + AsyncUserResource, + UserResourceWithRawResponse, + AsyncUserResourceWithRawResponse, + UserResourceWithStreamingResponse, + AsyncUserResourceWithStreamingResponse, +) +from .projects import ( + ProjectsResource, + AsyncProjectsResource, + ProjectsResourceWithRawResponse, + AsyncProjectsResourceWithRawResponse, + ProjectsResourceWithStreamingResponse, + AsyncProjectsResourceWithStreamingResponse, +) + +__all__ = [ + "ProjectsResource", + "AsyncProjectsResource", + "ProjectsResourceWithRawResponse", + "AsyncProjectsResourceWithRawResponse", + "ProjectsResourceWithStreamingResponse", + "AsyncProjectsResourceWithStreamingResponse", + "UserResource", + "AsyncUserResource", + "UserResourceWithRawResponse", + "AsyncUserResourceWithRawResponse", + "UserResourceWithStreamingResponse", + "AsyncUserResourceWithStreamingResponse", +] diff --git a/src/asktable/resources/user/projects.py b/src/asktable/resources/user/projects.py new file mode 100644 index 00000000..27ba7426 --- /dev/null +++ b/src/asktable/resources/user/projects.py @@ -0,0 +1,288 @@ +# 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.user import project_update_my_project_params +from ..._base_client import make_request_options +from ...types.sys.project import Project +from ...types.user.project_retrieve_model_groups_response import ProjectRetrieveModelGroupsResponse + +__all__ = ["ProjectsResource", "AsyncProjectsResource"] + + +class ProjectsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ProjectsResourceWithRawResponse: + """ + 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 ProjectsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ProjectsResourceWithStreamingResponse: + """ + 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 ProjectsResourceWithStreamingResponse(self) + + def retrieve_model_groups( + 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, + ) -> ProjectRetrieveModelGroupsResponse: + """Get Llm Model Groups""" + return self._get( + "/v1/user/projects/model-groups", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectRetrieveModelGroupsResponse, + ) + + def retrieve_my_project( + 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, + ) -> Project: + """Get My Project""" + return self._get( + "/v1/user/projects", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + def update_my_project( + self, + *, + llm_model_group: Optional[str] | NotGiven = NOT_GIVEN, + name: 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, + ) -> Project: + """ + Update My Project + + Args: + llm_model_group: 模型组 + + 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._patch( + "/v1/user/projects", + body=maybe_transform( + { + "llm_model_group": llm_model_group, + "name": name, + }, + project_update_my_project_params.ProjectUpdateMyProjectParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + +class AsyncProjectsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse: + """ + 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 AsyncProjectsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncProjectsResourceWithStreamingResponse: + """ + 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 AsyncProjectsResourceWithStreamingResponse(self) + + async def retrieve_model_groups( + 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, + ) -> ProjectRetrieveModelGroupsResponse: + """Get Llm Model Groups""" + return await self._get( + "/v1/user/projects/model-groups", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectRetrieveModelGroupsResponse, + ) + + async def retrieve_my_project( + 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, + ) -> Project: + """Get My Project""" + return await self._get( + "/v1/user/projects", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + async def update_my_project( + self, + *, + llm_model_group: Optional[str] | NotGiven = NOT_GIVEN, + name: 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, + ) -> Project: + """ + Update My Project + + Args: + llm_model_group: 模型组 + + 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._patch( + "/v1/user/projects", + body=await async_maybe_transform( + { + "llm_model_group": llm_model_group, + "name": name, + }, + project_update_my_project_params.ProjectUpdateMyProjectParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Project, + ) + + +class ProjectsResourceWithRawResponse: + def __init__(self, projects: ProjectsResource) -> None: + self._projects = projects + + self.retrieve_model_groups = to_raw_response_wrapper( + projects.retrieve_model_groups, + ) + self.retrieve_my_project = to_raw_response_wrapper( + projects.retrieve_my_project, + ) + self.update_my_project = to_raw_response_wrapper( + projects.update_my_project, + ) + + +class AsyncProjectsResourceWithRawResponse: + def __init__(self, projects: AsyncProjectsResource) -> None: + self._projects = projects + + self.retrieve_model_groups = async_to_raw_response_wrapper( + projects.retrieve_model_groups, + ) + self.retrieve_my_project = async_to_raw_response_wrapper( + projects.retrieve_my_project, + ) + self.update_my_project = async_to_raw_response_wrapper( + projects.update_my_project, + ) + + +class ProjectsResourceWithStreamingResponse: + def __init__(self, projects: ProjectsResource) -> None: + self._projects = projects + + self.retrieve_model_groups = to_streamed_response_wrapper( + projects.retrieve_model_groups, + ) + self.retrieve_my_project = to_streamed_response_wrapper( + projects.retrieve_my_project, + ) + self.update_my_project = to_streamed_response_wrapper( + projects.update_my_project, + ) + + +class AsyncProjectsResourceWithStreamingResponse: + def __init__(self, projects: AsyncProjectsResource) -> None: + self._projects = projects + + self.retrieve_model_groups = async_to_streamed_response_wrapper( + projects.retrieve_model_groups, + ) + self.retrieve_my_project = async_to_streamed_response_wrapper( + projects.retrieve_my_project, + ) + self.update_my_project = async_to_streamed_response_wrapper( + projects.update_my_project, + ) diff --git a/src/asktable/resources/user/user.py b/src/asktable/resources/user/user.py new file mode 100644 index 00000000..981d0969 --- /dev/null +++ b/src/asktable/resources/user/user.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .projects import ( + ProjectsResource, + AsyncProjectsResource, + ProjectsResourceWithRawResponse, + AsyncProjectsResourceWithRawResponse, + ProjectsResourceWithStreamingResponse, + AsyncProjectsResourceWithStreamingResponse, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource + +__all__ = ["UserResource", "AsyncUserResource"] + + +class UserResource(SyncAPIResource): + @cached_property + def projects(self) -> ProjectsResource: + return ProjectsResource(self._client) + + @cached_property + def with_raw_response(self) -> UserResourceWithRawResponse: + """ + 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 UserResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> UserResourceWithStreamingResponse: + """ + 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 UserResourceWithStreamingResponse(self) + + +class AsyncUserResource(AsyncAPIResource): + @cached_property + def projects(self) -> AsyncProjectsResource: + return AsyncProjectsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncUserResourceWithRawResponse: + """ + 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 AsyncUserResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncUserResourceWithStreamingResponse: + """ + 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 AsyncUserResourceWithStreamingResponse(self) + + +class UserResourceWithRawResponse: + def __init__(self, user: UserResource) -> None: + self._user = user + + @cached_property + def projects(self) -> ProjectsResourceWithRawResponse: + return ProjectsResourceWithRawResponse(self._user.projects) + + +class AsyncUserResourceWithRawResponse: + def __init__(self, user: AsyncUserResource) -> None: + self._user = user + + @cached_property + def projects(self) -> AsyncProjectsResourceWithRawResponse: + return AsyncProjectsResourceWithRawResponse(self._user.projects) + + +class UserResourceWithStreamingResponse: + def __init__(self, user: UserResource) -> None: + self._user = user + + @cached_property + def projects(self) -> ProjectsResourceWithStreamingResponse: + return ProjectsResourceWithStreamingResponse(self._user.projects) + + +class AsyncUserResourceWithStreamingResponse: + def __init__(self, user: AsyncUserResource) -> None: + self._user = user + + @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 19d3b17f..640c9f4b 100644 --- a/src/asktable/types/__init__.py +++ b/src/asktable/types/__init__.py @@ -7,7 +7,6 @@ from .role import Role as Role from .entry import Entry as Entry from .index import Index as Index -from .extapi import Extapi as Extapi from .shared import Policy as Policy from .chatbot import Chatbot as Chatbot from .ai_message import AIMessage as AIMessage @@ -17,11 +16,16 @@ 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 @@ -29,18 +33,18 @@ 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 .extapi_list_params import ExtapiListParams as ExtapiListParams 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 .extapi_create_params import ExtapiCreateParams as ExtapiCreateParams -from .extapi_update_params import ExtapiUpdateParams as ExtapiUpdateParams 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 @@ -50,6 +54,8 @@ 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 @@ -57,8 +63,10 @@ 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 .datasource_add_file_params import DatasourceAddFileParams as DatasourceAddFileParams from .preference_create_response import PreferenceCreateResponse as PreferenceCreateResponse from .preference_update_response import PreferenceUpdateResponse as PreferenceUpdateResponse diff --git a/src/asktable/types/ats/__init__.py b/src/asktable/types/ats/__init__.py new file mode 100644 index 00000000..bcd2ea3d --- /dev/null +++ b/src/asktable/types/ats/__init__.py @@ -0,0 +1,18 @@ +# 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 new file mode 100644 index 00000000..6b90d2a7 --- /dev/null +++ b/src/asktable/types/ats/task_get_case_tasks_params.py @@ -0,0 +1,17 @@ +# 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 new file mode 100644 index 00000000..0592193e --- /dev/null +++ b/src/asktable/types/ats/task_get_case_tasks_response.py @@ -0,0 +1,73 @@ +# 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/extapi_list_params.py b/src/asktable/types/ats/task_list_params.py similarity index 61% rename from src/asktable/types/extapi_list_params.py rename to src/asktable/types/ats/task_list_params.py index 01ba6bd1..8a9f52c2 100644 --- a/src/asktable/types/extapi_list_params.py +++ b/src/asktable/types/ats/task_list_params.py @@ -2,16 +2,12 @@ from __future__ import annotations -from typing import Optional from typing_extensions import TypedDict -__all__ = ["ExtapiListParams"] +__all__ = ["TaskListParams"] -class ExtapiListParams(TypedDict, total=False): - name: Optional[str] - """名称""" - +class TaskListParams(TypedDict, total=False): page: int """Page number""" diff --git a/src/asktable/types/ats/task_list_response.py b/src/asktable/types/ats/task_list_response.py new file mode 100644 index 00000000..a3591ca0 --- /dev/null +++ b/src/asktable/types/ats/task_list_response.py @@ -0,0 +1,49 @@ +# 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 new file mode 100644 index 00000000..bc81d5bc --- /dev/null +++ b/src/asktable/types/ats/task_retrieve_response.py @@ -0,0 +1,49 @@ +# 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 new file mode 100644 index 00000000..b86b4193 --- /dev/null +++ b/src/asktable/types/ats/task_run_params.py @@ -0,0 +1,16 @@ +# 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 new file mode 100644 index 00000000..fbc3533c --- /dev/null +++ b/src/asktable/types/ats/task_run_response.py @@ -0,0 +1,49 @@ +# 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 new file mode 100644 index 00000000..229132b2 --- /dev/null +++ b/src/asktable/types/ats/test_case_create_params.py @@ -0,0 +1,22 @@ +# 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 new file mode 100644 index 00000000..0faa6a83 --- /dev/null +++ b/src/asktable/types/ats/test_case_create_response.py @@ -0,0 +1,35 @@ +# 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 new file mode 100644 index 00000000..603b4898 --- /dev/null +++ b/src/asktable/types/ats/test_case_list_params.py @@ -0,0 +1,15 @@ +# 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 new file mode 100644 index 00000000..4216c794 --- /dev/null +++ b/src/asktable/types/ats/test_case_list_response.py @@ -0,0 +1,35 @@ +# 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 new file mode 100644 index 00000000..951aee1d --- /dev/null +++ b/src/asktable/types/ats/test_case_retrieve_response.py @@ -0,0 +1,35 @@ +# 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 new file mode 100644 index 00000000..020118e0 --- /dev/null +++ b/src/asktable/types/ats/test_case_update_params.py @@ -0,0 +1,24 @@ +# 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 new file mode 100644 index 00000000..089d55e8 --- /dev/null +++ b/src/asktable/types/ats/test_case_update_response.py @@ -0,0 +1,35 @@ +# 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 new file mode 100644 index 00000000..64ea530f --- /dev/null +++ b/src/asktable/types/ats_create_params.py @@ -0,0 +1,15 @@ +# 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 new file mode 100644 index 00000000..4ed69a97 --- /dev/null +++ b/src/asktable/types/ats_create_response.py @@ -0,0 +1,27 @@ +# 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 new file mode 100644 index 00000000..e8eef511 --- /dev/null +++ b/src/asktable/types/ats_delete_params.py @@ -0,0 +1,12 @@ +# 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 new file mode 100644 index 00000000..09110362 --- /dev/null +++ b/src/asktable/types/ats_list_params.py @@ -0,0 +1,18 @@ +# 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 new file mode 100644 index 00000000..04206289 --- /dev/null +++ b/src/asktable/types/ats_list_response.py @@ -0,0 +1,27 @@ +# 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 new file mode 100644 index 00000000..0195c97c --- /dev/null +++ b/src/asktable/types/ats_retrieve_response.py @@ -0,0 +1,27 @@ +# 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 new file mode 100644 index 00000000..3b1cdbba --- /dev/null +++ b/src/asktable/types/ats_update_params.py @@ -0,0 +1,12 @@ +# 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 new file mode 100644 index 00000000..374dfe87 --- /dev/null +++ b/src/asktable/types/ats_update_response.py @@ -0,0 +1,27 @@ +# 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/extapi.py b/src/asktable/types/extapi.py deleted file mode 100644 index 902ffbf0..00000000 --- a/src/asktable/types/extapi.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["Extapi"] - - -class Extapi(BaseModel): - id: str - - base_url: str - """根 URL""" - - created_at: datetime - - name: str - """名称,不超过 64 个字符""" - - project_id: str - - updated_at: datetime - - headers: Optional[Dict[str, str]] = None - """HTTP Headers,JSON 格式""" diff --git a/src/asktable/types/extapi_create_params.py b/src/asktable/types/extapi_create_params.py deleted file mode 100644 index 77a795f4..00000000 --- a/src/asktable/types/extapi_create_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 Dict, Optional -from typing_extensions import Required, TypedDict - -__all__ = ["ExtapiCreateParams"] - - -class ExtapiCreateParams(TypedDict, total=False): - base_url: Required[str] - """根 URL""" - - name: Required[str] - """名称,不超过 64 个字符""" - - headers: Optional[Dict[str, str]] - """HTTP Headers,JSON 格式""" diff --git a/src/asktable/types/extapi_update_params.py b/src/asktable/types/extapi_update_params.py deleted file mode 100644 index e950b195..00000000 --- a/src/asktable/types/extapi_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 Dict, Optional -from typing_extensions import TypedDict - -__all__ = ["ExtapiUpdateParams"] - - -class ExtapiUpdateParams(TypedDict, total=False): - base_url: Optional[str] - """根 URL""" - - headers: Optional[Dict[str, str]] - """HTTP Headers,JSON 格式""" - - name: Optional[str] - """名称,不超过 64 个字符""" diff --git a/src/asktable/types/extapis/__init__.py b/src/asktable/types/extapis/__init__.py deleted file mode 100644 index fbd63ce0..00000000 --- a/src/asktable/types/extapis/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .extapi_route import ExtapiRoute as ExtapiRoute -from .route_create_params import RouteCreateParams as RouteCreateParams -from .route_list_response import RouteListResponse as RouteListResponse -from .route_update_params import RouteUpdateParams as RouteUpdateParams diff --git a/src/asktable/types/extapis/extapi_route.py b/src/asktable/types/extapis/extapi_route.py deleted file mode 100644 index 299a7c94..00000000 --- a/src/asktable/types/extapis/extapi_route.py +++ /dev/null @@ -1,39 +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__ = ["ExtapiRoute"] - - -class ExtapiRoute(BaseModel): - id: str - - created_at: datetime - - extapi_id: str - - method: Literal["GET", "POST", "PUT", "DELETE"] - """HTTP 方法""" - - name: str - """API 方法名称,不超过 64 个字符""" - - path: str - """API 路径""" - - project_id: str - - updated_at: datetime - - body_params_desc: Optional[str] = None - """请求体参数描述""" - - path_params_desc: Optional[str] = None - """路径参数描述""" - - query_params_desc: Optional[str] = None - """查询参数描述""" diff --git a/src/asktable/types/extapis/route_create_params.py b/src/asktable/types/extapis/route_create_params.py deleted file mode 100644 index e58f6e3e..00000000 --- a/src/asktable/types/extapis/route_create_params.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["RouteCreateParams"] - - -class RouteCreateParams(TypedDict, total=False): - id: Required[str] - - created_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - body_extapi_id: Required[Annotated[str, PropertyInfo(alias="extapi_id")]] - - method: Required[Literal["GET", "POST", "PUT", "DELETE"]] - """HTTP 方法""" - - name: Required[str] - """API 方法名称,不超过 64 个字符""" - - path: Required[str] - """API 路径""" - - project_id: Required[str] - - updated_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - body_params_desc: Optional[str] - """请求体参数描述""" - - path_params_desc: Optional[str] - """路径参数描述""" - - query_params_desc: Optional[str] - """查询参数描述""" diff --git a/src/asktable/types/extapis/route_list_response.py b/src/asktable/types/extapis/route_list_response.py deleted file mode 100644 index 5a38d0b2..00000000 --- a/src/asktable/types/extapis/route_list_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 .extapi_route import ExtapiRoute - -__all__ = ["RouteListResponse"] - -RouteListResponse: TypeAlias = List[ExtapiRoute] diff --git a/src/asktable/types/extapis/route_update_params.py b/src/asktable/types/extapis/route_update_params.py deleted file mode 100644 index c75ce0d7..00000000 --- a/src/asktable/types/extapis/route_update_params.py +++ /dev/null @@ -1,30 +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 Literal, Required, TypedDict - -__all__ = ["RouteUpdateParams"] - - -class RouteUpdateParams(TypedDict, total=False): - extapi_id: Required[str] - - body_params_desc: Optional[str] - """请求体参数描述""" - - method: Optional[Literal["GET", "POST", "PUT", "DELETE"]] - """HTTP 方法""" - - name: Optional[str] - """API 方法名称,不超过 64 个字符""" - - path: Optional[str] - """API 路径""" - - path_params_desc: Optional[str] - """路径参数描述""" - - query_params_desc: Optional[str] - """查询参数描述""" diff --git a/src/asktable/types/sy_update_config_params.py b/src/asktable/types/sy_update_config_params.py new file mode 100644 index 00000000..fd7c7246 --- /dev/null +++ b/src/asktable/types/sy_update_config_params.py @@ -0,0 +1,13 @@ +# 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 new file mode 100644 index 00000000..9d77316d --- /dev/null +++ b/src/asktable/types/sy_update_config_response.py @@ -0,0 +1,12 @@ +# 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 a55ccaa2..603cf14d 100644 --- a/src/asktable/types/sys/__init__.py +++ b/src/asktable/types/sys/__init__.py @@ -7,5 +7,6 @@ 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_model_groups_response import ProjectModelGroupsResponse as ProjectModelGroupsResponse diff --git a/src/asktable/types/sys/project_import_params.py b/src/asktable/types/sys/project_import_params.py new file mode 100644 index 00000000..d244232a --- /dev/null +++ b/src/asktable/types/sys/project_import_params.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ProjectImportParams"] + + +class ProjectImportParams(TypedDict, total=False): + body: Required[object] diff --git a/src/asktable/types/training_update_params.py b/src/asktable/types/training_update_params.py new file mode 100644 index 00000000..82d56a3f --- /dev/null +++ b/src/asktable/types/training_update_params.py @@ -0,0 +1,25 @@ +# 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 new file mode 100644 index 00000000..3817394d --- /dev/null +++ b/src/asktable/types/training_update_response.py @@ -0,0 +1,47 @@ +# 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/__init__.py b/src/asktable/types/user/__init__.py new file mode 100644 index 00000000..1a494b06 --- /dev/null +++ b/src/asktable/types/user/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .project_update_my_project_params import ProjectUpdateMyProjectParams as ProjectUpdateMyProjectParams +from .project_retrieve_model_groups_response import ( + ProjectRetrieveModelGroupsResponse as ProjectRetrieveModelGroupsResponse, +) diff --git a/src/asktable/types/user/project_retrieve_model_groups_response.py b/src/asktable/types/user/project_retrieve_model_groups_response.py new file mode 100644 index 00000000..d2f36279 --- /dev/null +++ b/src/asktable/types/user/project_retrieve_model_groups_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from ..sys.model_group import ModelGroup + +__all__ = ["ProjectRetrieveModelGroupsResponse"] + +ProjectRetrieveModelGroupsResponse: TypeAlias = List[ModelGroup] diff --git a/src/asktable/types/user/project_update_my_project_params.py b/src/asktable/types/user/project_update_my_project_params.py new file mode 100644 index 00000000..c7936a3c --- /dev/null +++ b/src/asktable/types/user/project_update_my_project_params.py @@ -0,0 +1,16 @@ +# 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__ = ["ProjectUpdateMyProjectParams"] + + +class ProjectUpdateMyProjectParams(TypedDict, total=False): + llm_model_group: Optional[str] + """模型组""" + + name: Optional[str] + """项目名称""" diff --git a/tests/api_resources/extapis/__init__.py b/tests/api_resources/ats/__init__.py similarity index 100% rename from tests/api_resources/extapis/__init__.py rename to tests/api_resources/ats/__init__.py diff --git a/tests/api_resources/ats/test_task.py b/tests/api_resources/ats/test_task.py new file mode 100644 index 00000000..9479b977 --- /dev/null +++ b/tests/api_resources/ats/test_task.py @@ -0,0 +1,428 @@ +# 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 new file mode 100644 index 00000000..7a9a1281 --- /dev/null +++ b/tests/api_resources/ats/test_test_case.py @@ -0,0 +1,570 @@ +# 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/extapis/test_routes.py b/tests/api_resources/extapis/test_routes.py deleted file mode 100644 index aae62f3f..00000000 --- a/tests/api_resources/extapis/test_routes.py +++ /dev/null @@ -1,593 +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._utils import parse_datetime -from asktable.types.extapis import ExtapiRoute, RouteListResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestRoutes: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Asktable) -> None: - route = client.extapis.routes.create( - path_extapi_id="extapi_id", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - route = client.extapis.routes.create( - path_extapi_id="extapi_id", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_params_desc="body_params_desc", - path_params_desc="path_params_desc", - query_params_desc="query_params_desc", - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Asktable) -> None: - response = client.extapis.routes.with_raw_response.create( - path_extapi_id="extapi_id", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = response.parse() - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Asktable) -> None: - with client.extapis.routes.with_streaming_response.create( - path_extapi_id="extapi_id", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = response.parse() - assert_matches_type(ExtapiRoute, route, 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 `path_extapi_id` but received ''"): - client.extapis.routes.with_raw_response.create( - path_extapi_id="", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - @parametrize - def test_method_retrieve(self, client: Asktable) -> None: - route = client.extapis.routes.retrieve( - route_id="route_id", - extapi_id="extapi_id", - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.extapis.routes.with_raw_response.retrieve( - route_id="route_id", - extapi_id="extapi_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = response.parse() - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.extapis.routes.with_streaming_response.retrieve( - route_id="route_id", - extapi_id="extapi_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = response.parse() - assert_matches_type(ExtapiRoute, route, 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 `extapi_id` but received ''"): - client.extapis.routes.with_raw_response.retrieve( - route_id="route_id", - extapi_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `route_id` but received ''"): - client.extapis.routes.with_raw_response.retrieve( - route_id="", - extapi_id="extapi_id", - ) - - @parametrize - def test_method_update(self, client: Asktable) -> None: - route = client.extapis.routes.update( - route_id="route_id", - extapi_id="extapi_id", - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - route = client.extapis.routes.update( - route_id="route_id", - extapi_id="extapi_id", - body_params_desc="body_params_desc", - method="GET", - name="name", - path="/resource", - path_params_desc="path_params_desc", - query_params_desc="query_params_desc", - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Asktable) -> None: - response = client.extapis.routes.with_raw_response.update( - route_id="route_id", - extapi_id="extapi_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = response.parse() - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Asktable) -> None: - with client.extapis.routes.with_streaming_response.update( - route_id="route_id", - extapi_id="extapi_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = response.parse() - assert_matches_type(ExtapiRoute, route, 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 `extapi_id` but received ''"): - client.extapis.routes.with_raw_response.update( - route_id="route_id", - extapi_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `route_id` but received ''"): - client.extapis.routes.with_raw_response.update( - route_id="", - extapi_id="extapi_id", - ) - - @parametrize - def test_method_list(self, client: Asktable) -> None: - route = client.extapis.routes.list( - "extapi_id", - ) - assert_matches_type(RouteListResponse, route, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Asktable) -> None: - response = client.extapis.routes.with_raw_response.list( - "extapi_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = response.parse() - assert_matches_type(RouteListResponse, route, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Asktable) -> None: - with client.extapis.routes.with_streaming_response.list( - "extapi_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = response.parse() - assert_matches_type(RouteListResponse, route, 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 `extapi_id` but received ''"): - client.extapis.routes.with_raw_response.list( - "", - ) - - @parametrize - def test_method_delete(self, client: Asktable) -> None: - route = client.extapis.routes.delete( - route_id="route_id", - extapi_id="extapi_id", - ) - assert route is None - - @parametrize - def test_raw_response_delete(self, client: Asktable) -> None: - response = client.extapis.routes.with_raw_response.delete( - route_id="route_id", - extapi_id="extapi_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = response.parse() - assert route is None - - @parametrize - def test_streaming_response_delete(self, client: Asktable) -> None: - with client.extapis.routes.with_streaming_response.delete( - route_id="route_id", - extapi_id="extapi_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = response.parse() - assert route 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 `extapi_id` but received ''"): - client.extapis.routes.with_raw_response.delete( - route_id="route_id", - extapi_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `route_id` but received ''"): - client.extapis.routes.with_raw_response.delete( - route_id="", - extapi_id="extapi_id", - ) - - -class TestAsyncRoutes: - 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: - route = await async_client.extapis.routes.create( - path_extapi_id="extapi_id", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - route = await async_client.extapis.routes.create( - path_extapi_id="extapi_id", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_params_desc="body_params_desc", - path_params_desc="path_params_desc", - query_params_desc="query_params_desc", - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.routes.with_raw_response.create( - path_extapi_id="extapi_id", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = await response.parse() - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncAsktable) -> None: - async with async_client.extapis.routes.with_streaming_response.create( - path_extapi_id="extapi_id", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = await response.parse() - assert_matches_type(ExtapiRoute, route, 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 `path_extapi_id` but received ''"): - await async_client.extapis.routes.with_raw_response.create( - path_extapi_id="", - id="id", - created_at=parse_datetime("2019-12-27T18:11:19.117Z"), - body_extapi_id="extapi_id", - method="GET", - name="name", - path="/resource", - project_id="project_id", - updated_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncAsktable) -> None: - route = await async_client.extapis.routes.retrieve( - route_id="route_id", - extapi_id="extapi_id", - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.routes.with_raw_response.retrieve( - route_id="route_id", - extapi_id="extapi_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = await response.parse() - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncAsktable) -> None: - async with async_client.extapis.routes.with_streaming_response.retrieve( - route_id="route_id", - extapi_id="extapi_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = await response.parse() - assert_matches_type(ExtapiRoute, route, 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 `extapi_id` but received ''"): - await async_client.extapis.routes.with_raw_response.retrieve( - route_id="route_id", - extapi_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `route_id` but received ''"): - await async_client.extapis.routes.with_raw_response.retrieve( - route_id="", - extapi_id="extapi_id", - ) - - @parametrize - async def test_method_update(self, async_client: AsyncAsktable) -> None: - route = await async_client.extapis.routes.update( - route_id="route_id", - extapi_id="extapi_id", - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - route = await async_client.extapis.routes.update( - route_id="route_id", - extapi_id="extapi_id", - body_params_desc="body_params_desc", - method="GET", - name="name", - path="/resource", - path_params_desc="path_params_desc", - query_params_desc="query_params_desc", - ) - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.routes.with_raw_response.update( - route_id="route_id", - extapi_id="extapi_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = await response.parse() - assert_matches_type(ExtapiRoute, route, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncAsktable) -> None: - async with async_client.extapis.routes.with_streaming_response.update( - route_id="route_id", - extapi_id="extapi_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = await response.parse() - assert_matches_type(ExtapiRoute, route, 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 `extapi_id` but received ''"): - await async_client.extapis.routes.with_raw_response.update( - route_id="route_id", - extapi_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `route_id` but received ''"): - await async_client.extapis.routes.with_raw_response.update( - route_id="", - extapi_id="extapi_id", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncAsktable) -> None: - route = await async_client.extapis.routes.list( - "extapi_id", - ) - assert_matches_type(RouteListResponse, route, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.routes.with_raw_response.list( - "extapi_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = await response.parse() - assert_matches_type(RouteListResponse, route, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncAsktable) -> None: - async with async_client.extapis.routes.with_streaming_response.list( - "extapi_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = await response.parse() - assert_matches_type(RouteListResponse, route, 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 `extapi_id` but received ''"): - await async_client.extapis.routes.with_raw_response.list( - "", - ) - - @parametrize - async def test_method_delete(self, async_client: AsyncAsktable) -> None: - route = await async_client.extapis.routes.delete( - route_id="route_id", - extapi_id="extapi_id", - ) - assert route is None - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.routes.with_raw_response.delete( - route_id="route_id", - extapi_id="extapi_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - route = await response.parse() - assert route is None - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncAsktable) -> None: - async with async_client.extapis.routes.with_streaming_response.delete( - route_id="route_id", - extapi_id="extapi_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - route = await response.parse() - assert route 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 `extapi_id` but received ''"): - await async_client.extapis.routes.with_raw_response.delete( - route_id="route_id", - extapi_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `route_id` but received ''"): - await async_client.extapis.routes.with_raw_response.delete( - route_id="", - extapi_id="extapi_id", - ) diff --git a/tests/api_resources/sys/test_projects.py b/tests/api_resources/sys/test_projects.py index 274bc826..8b8d87c3 100644 --- a/tests/api_resources/sys/test_projects.py +++ b/tests/api_resources/sys/test_projects.py @@ -210,6 +210,75 @@ def test_path_params_delete(self, client: Asktable) -> None: "", ) + @parametrize + def test_method_export(self, client: Asktable) -> None: + project = client.sys.projects.export( + "project_id", + ) + assert_matches_type(object, project, path=["response"]) + + @parametrize + def test_raw_response_export(self, client: Asktable) -> None: + response = client.sys.projects.with_raw_response.export( + "project_id", + ) + + 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"]) + + @parametrize + def test_streaming_response_export(self, client: Asktable) -> None: + with client.sys.projects.with_streaming_response.export( + "project_id", + ) 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 cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_export(self, client: Asktable) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.sys.projects.with_raw_response.export( + "", + ) + + @parametrize + def test_method_import(self, client: Asktable) -> None: + project = client.sys.projects.import_( + body={}, + ) + assert_matches_type(object, project, path=["response"]) + + @parametrize + def test_raw_response_import(self, client: Asktable) -> None: + response = client.sys.projects.with_raw_response.import_( + body={}, + ) + + 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"]) + + @parametrize + def test_streaming_response_import(self, client: Asktable) -> None: + with client.sys.projects.with_streaming_response.import_( + body={}, + ) 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 cast(Any, response.is_closed) is True + @parametrize def test_method_model_groups(self, client: Asktable) -> None: project = client.sys.projects.model_groups() @@ -430,6 +499,75 @@ async def test_path_params_delete(self, async_client: AsyncAsktable) -> None: "", ) + @parametrize + 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"]) + + @parametrize + async def test_raw_response_export(self, async_client: AsyncAsktable) -> None: + response = await async_client.sys.projects.with_raw_response.export( + "project_id", + ) + + 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"]) + + @parametrize + async def test_streaming_response_export(self, async_client: AsyncAsktable) -> None: + async with async_client.sys.projects.with_streaming_response.export( + "project_id", + ) 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 cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_export(self, async_client: AsyncAsktable) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.sys.projects.with_raw_response.export( + "", + ) + + @parametrize + async def test_method_import(self, async_client: AsyncAsktable) -> None: + project = await async_client.sys.projects.import_( + body={}, + ) + assert_matches_type(object, 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={}, + ) + + 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"]) + + @parametrize + async def test_streaming_response_import(self, async_client: AsyncAsktable) -> None: + async with async_client.sys.projects.with_streaming_response.import_( + body={}, + ) 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 cast(Any, response.is_closed) is True + @parametrize async def test_method_model_groups(self, async_client: AsyncAsktable) -> None: project = await async_client.sys.projects.model_groups() diff --git a/tests/api_resources/test_extapis.py b/tests/api_resources/test_ats.py similarity index 52% rename from tests/api_resources/test_extapis.py rename to tests/api_resources/test_ats.py index ec717cf0..7dc37e89 100644 --- a/tests/api_resources/test_extapis.py +++ b/tests/api_resources/test_ats.py @@ -9,419 +9,414 @@ from asktable import Asktable, AsyncAsktable from tests.utils import assert_matches_type -from asktable.types import Extapi +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 TestExtapis: +class TestATS: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize def test_method_create(self, client: Asktable) -> None: - extapi = client.extapis.create( - base_url="https://api.example.com/v1", + ats = client.ats.create( + datasource_id="datasource_id", name="name", ) - assert_matches_type(Extapi, extapi, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Asktable) -> None: - extapi = client.extapis.create( - base_url="https://api.example.com/v1", - name="name", - headers={"Authorization": "Bearer "}, - ) - assert_matches_type(Extapi, extapi, path=["response"]) + assert_matches_type(ATSCreateResponse, ats, path=["response"]) @parametrize def test_raw_response_create(self, client: Asktable) -> None: - response = client.extapis.with_raw_response.create( - base_url="https://api.example.com/v1", + 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" - extapi = response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + ats = response.parse() + assert_matches_type(ATSCreateResponse, ats, path=["response"]) @parametrize def test_streaming_response_create(self, client: Asktable) -> None: - with client.extapis.with_streaming_response.create( - base_url="https://api.example.com/v1", + 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" - extapi = response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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: - extapi = client.extapis.retrieve( - "extapi_id", + ats = client.ats.retrieve( + "ats_id", ) - assert_matches_type(Extapi, extapi, path=["response"]) + assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: Asktable) -> None: - response = client.extapis.with_raw_response.retrieve( - "extapi_id", + 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" - extapi = response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + ats = response.parse() + assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) @parametrize def test_streaming_response_retrieve(self, client: Asktable) -> None: - with client.extapis.with_streaming_response.retrieve( - "extapi_id", + 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" - extapi = response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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 `extapi_id` but received ''"): - client.extapis.with_raw_response.retrieve( + 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: - extapi = client.extapis.update( - extapi_id="extapi_id", - ) - assert_matches_type(Extapi, extapi, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Asktable) -> None: - extapi = client.extapis.update( - extapi_id="extapi_id", - base_url="https://api.example.com/v1", - headers={"Authorization": "Bearer "}, + ats = client.ats.update( + ats_id="ats_id", name="name", ) - assert_matches_type(Extapi, extapi, path=["response"]) + assert_matches_type(ATSUpdateResponse, ats, path=["response"]) @parametrize def test_raw_response_update(self, client: Asktable) -> None: - response = client.extapis.with_raw_response.update( - extapi_id="extapi_id", + 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" - extapi = response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + ats = response.parse() + assert_matches_type(ATSUpdateResponse, ats, path=["response"]) @parametrize def test_streaming_response_update(self, client: Asktable) -> None: - with client.extapis.with_streaming_response.update( - extapi_id="extapi_id", + 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" - extapi = response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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 `extapi_id` but received ''"): - client.extapis.with_raw_response.update( - extapi_id="", + 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: - extapi = client.extapis.list() - assert_matches_type(SyncPage[Extapi], extapi, path=["response"]) + 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: - extapi = client.extapis.list( - name="name", + ats = client.ats.list( + datasource_id="datasource_id", page=1, size=1, ) - assert_matches_type(SyncPage[Extapi], extapi, path=["response"]) + assert_matches_type(SyncPage[ATSListResponse], ats, path=["response"]) @parametrize def test_raw_response_list(self, client: Asktable) -> None: - response = client.extapis.with_raw_response.list() + 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" - extapi = response.parse() - assert_matches_type(SyncPage[Extapi], extapi, path=["response"]) + ats = response.parse() + assert_matches_type(SyncPage[ATSListResponse], ats, path=["response"]) @parametrize def test_streaming_response_list(self, client: Asktable) -> None: - with client.extapis.with_streaming_response.list() as response: + 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" - extapi = response.parse() - assert_matches_type(SyncPage[Extapi], extapi, path=["response"]) + 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: - extapi = client.extapis.delete( - "extapi_id", + ats = client.ats.delete( + ats_id="ats_id", + datasource_id="datasource_id", ) - assert_matches_type(object, extapi, path=["response"]) + assert_matches_type(object, ats, path=["response"]) @parametrize def test_raw_response_delete(self, client: Asktable) -> None: - response = client.extapis.with_raw_response.delete( - "extapi_id", + 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" - extapi = response.parse() - assert_matches_type(object, extapi, path=["response"]) + ats = response.parse() + assert_matches_type(object, ats, path=["response"]) @parametrize def test_streaming_response_delete(self, client: Asktable) -> None: - with client.extapis.with_streaming_response.delete( - "extapi_id", + 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" - extapi = response.parse() - assert_matches_type(object, extapi, path=["response"]) + 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 `extapi_id` but received ''"): - client.extapis.with_raw_response.delete( - "", + 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 TestAsyncExtapis: +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: - extapi = await async_client.extapis.create( - base_url="https://api.example.com/v1", + ats = await async_client.ats.create( + datasource_id="datasource_id", name="name", ) - assert_matches_type(Extapi, extapi, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncAsktable) -> None: - extapi = await async_client.extapis.create( - base_url="https://api.example.com/v1", - name="name", - headers={"Authorization": "Bearer "}, - ) - assert_matches_type(Extapi, extapi, path=["response"]) + assert_matches_type(ATSCreateResponse, ats, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.with_raw_response.create( - base_url="https://api.example.com/v1", + 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" - extapi = await response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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.extapis.with_streaming_response.create( - base_url="https://api.example.com/v1", + 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" - extapi = await response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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: - extapi = await async_client.extapis.retrieve( - "extapi_id", + ats = await async_client.ats.retrieve( + "ats_id", ) - assert_matches_type(Extapi, extapi, path=["response"]) + assert_matches_type(ATSRetrieveResponse, ats, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.with_raw_response.retrieve( - "extapi_id", + 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" - extapi = await response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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.extapis.with_streaming_response.retrieve( - "extapi_id", + 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" - extapi = await response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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 `extapi_id` but received ''"): - await async_client.extapis.with_raw_response.retrieve( + 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: - extapi = await async_client.extapis.update( - extapi_id="extapi_id", - ) - assert_matches_type(Extapi, extapi, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncAsktable) -> None: - extapi = await async_client.extapis.update( - extapi_id="extapi_id", - base_url="https://api.example.com/v1", - headers={"Authorization": "Bearer "}, + ats = await async_client.ats.update( + ats_id="ats_id", name="name", ) - assert_matches_type(Extapi, extapi, path=["response"]) + assert_matches_type(ATSUpdateResponse, ats, path=["response"]) @parametrize async def test_raw_response_update(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.with_raw_response.update( - extapi_id="extapi_id", + 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" - extapi = await response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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.extapis.with_streaming_response.update( - extapi_id="extapi_id", + 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" - extapi = await response.parse() - assert_matches_type(Extapi, extapi, path=["response"]) + 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 `extapi_id` but received ''"): - await async_client.extapis.with_raw_response.update( - extapi_id="", + 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: - extapi = await async_client.extapis.list() - assert_matches_type(AsyncPage[Extapi], extapi, path=["response"]) + 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: - extapi = await async_client.extapis.list( - name="name", + ats = await async_client.ats.list( + datasource_id="datasource_id", page=1, size=1, ) - assert_matches_type(AsyncPage[Extapi], extapi, path=["response"]) + assert_matches_type(AsyncPage[ATSListResponse], ats, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.with_raw_response.list() + 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" - extapi = await response.parse() - assert_matches_type(AsyncPage[Extapi], extapi, path=["response"]) + 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.extapis.with_streaming_response.list() as response: + 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" - extapi = await response.parse() - assert_matches_type(AsyncPage[Extapi], extapi, path=["response"]) + 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: - extapi = await async_client.extapis.delete( - "extapi_id", + ats = await async_client.ats.delete( + ats_id="ats_id", + datasource_id="datasource_id", ) - assert_matches_type(object, extapi, path=["response"]) + assert_matches_type(object, ats, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncAsktable) -> None: - response = await async_client.extapis.with_raw_response.delete( - "extapi_id", + 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" - extapi = await response.parse() - assert_matches_type(object, extapi, path=["response"]) + 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.extapis.with_streaming_response.delete( - "extapi_id", + 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" - extapi = await response.parse() - assert_matches_type(object, extapi, path=["response"]) + 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 `extapi_id` but received ''"): - await async_client.extapis.with_raw_response.delete( - "", + 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_sys.py b/tests/api_resources/test_sys.py new file mode 100644 index 00000000..67abf960 --- /dev/null +++ b/tests/api_resources/test_sys.py @@ -0,0 +1,88 @@ +# 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 index c3f065e4..33452ed1 100644 --- a/tests/api_resources/test_trainings.py +++ b/tests/api_resources/test_trainings.py @@ -12,6 +12,7 @@ from asktable.types import ( TrainingListResponse, TrainingCreateResponse, + TrainingUpdateResponse, ) from asktable.pagination import SyncPage, AsyncPage @@ -70,6 +71,60 @@ def test_streaming_response_create(self, client: Asktable) -> None: 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( @@ -207,6 +262,60 @@ async def test_streaming_response_create(self, async_client: AsyncAsktable) -> N 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( diff --git a/tests/api_resources/user/__init__.py b/tests/api_resources/user/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/user/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/user/test_projects.py b/tests/api_resources/user/test_projects.py new file mode 100644 index 00000000..7be8c61c --- /dev/null +++ b/tests/api_resources/user/test_projects.py @@ -0,0 +1,191 @@ +# 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.sys import Project +from asktable.types.user import ProjectRetrieveModelGroupsResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestProjects: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve_model_groups(self, client: Asktable) -> None: + project = client.user.projects.retrieve_model_groups() + assert_matches_type(ProjectRetrieveModelGroupsResponse, project, path=["response"]) + + @parametrize + def test_raw_response_retrieve_model_groups(self, client: Asktable) -> None: + response = client.user.projects.with_raw_response.retrieve_model_groups() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(ProjectRetrieveModelGroupsResponse, project, path=["response"]) + + @parametrize + def test_streaming_response_retrieve_model_groups(self, client: Asktable) -> None: + with client.user.projects.with_streaming_response.retrieve_model_groups() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(ProjectRetrieveModelGroupsResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve_my_project(self, client: Asktable) -> None: + project = client.user.projects.retrieve_my_project() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_retrieve_my_project(self, client: Asktable) -> None: + response = client.user.projects.with_raw_response.retrieve_my_project() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_retrieve_my_project(self, client: Asktable) -> None: + with client.user.projects.with_streaming_response.retrieve_my_project() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_update_my_project(self, client: Asktable) -> None: + project = client.user.projects.update_my_project() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_method_update_my_project_with_all_params(self, client: Asktable) -> None: + project = client.user.projects.update_my_project( + llm_model_group="llm_model_group", + name="name", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_raw_response_update_my_project(self, client: Asktable) -> None: + response = client.user.projects.with_raw_response.update_my_project() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + def test_streaming_response_update_my_project(self, client: Asktable) -> None: + with client.user.projects.with_streaming_response.update_my_project() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncProjects: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_retrieve_model_groups(self, async_client: AsyncAsktable) -> None: + project = await async_client.user.projects.retrieve_model_groups() + assert_matches_type(ProjectRetrieveModelGroupsResponse, project, path=["response"]) + + @parametrize + async def test_raw_response_retrieve_model_groups(self, async_client: AsyncAsktable) -> None: + response = await async_client.user.projects.with_raw_response.retrieve_model_groups() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(ProjectRetrieveModelGroupsResponse, project, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve_model_groups(self, async_client: AsyncAsktable) -> None: + async with async_client.user.projects.with_streaming_response.retrieve_model_groups() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(ProjectRetrieveModelGroupsResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve_my_project(self, async_client: AsyncAsktable) -> None: + project = await async_client.user.projects.retrieve_my_project() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_retrieve_my_project(self, async_client: AsyncAsktable) -> None: + response = await async_client.user.projects.with_raw_response.retrieve_my_project() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve_my_project(self, async_client: AsyncAsktable) -> None: + async with async_client.user.projects.with_streaming_response.retrieve_my_project() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_update_my_project(self, async_client: AsyncAsktable) -> None: + project = await async_client.user.projects.update_my_project() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_method_update_my_project_with_all_params(self, async_client: AsyncAsktable) -> None: + project = await async_client.user.projects.update_my_project( + llm_model_group="llm_model_group", + name="name", + ) + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_raw_response_update_my_project(self, async_client: AsyncAsktable) -> None: + response = await async_client.user.projects.with_raw_response.update_my_project() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + @parametrize + async def test_streaming_response_update_my_project(self, async_client: AsyncAsktable) -> None: + async with async_client.user.projects.with_streaming_response.update_my_project() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(Project, project, path=["response"]) + + assert cast(Any, response.is_closed) is True From b8f0491dcfd698b1ba6212ee5784f4e107c7fea4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 19 Jul 2025 04:27:06 +0000 Subject: [PATCH 35/35] release: 5.5.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 48 +++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/asktable/_version.py | 2 +- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5f7bf255..f425d970 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "5.4.0" + ".": "5.5.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 820ef2c6..320a4033 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,53 @@ # Changelog +## 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) + +### Features + +* **api:** add test set api ([cf653ef](https://github.com/DataMini/asktable-python/commit/cf653ef0d527894151c209f7eb79b120e8d7109c)) +* **api:** api update ([d7a73bc](https://github.com/DataMini/asktable-python/commit/d7a73bceb38896da2565dd7e1ae8a3e39529a685)) +* clean up environment call outs ([6002d27](https://github.com/DataMini/asktable-python/commit/6002d277b7004e7fdd69f8b23572cf84a6cf10da)) +* **client:** add follow_redirects request option ([b22320b](https://github.com/DataMini/asktable-python/commit/b22320bad43f0de89af6d252c36902b2cd08ec97)) +* **client:** add support for aiohttp ([292b89e](https://github.com/DataMini/asktable-python/commit/292b89e54d3215237251f84ebbae97d4cbf65310)) + + +### Bug Fixes + +* **ci:** correct conditional ([b23a053](https://github.com/DataMini/asktable-python/commit/b23a0530daffe5b27939e7ab9516790f6fb36a7b)) +* **ci:** release-doctor — report correct token name ([71f15b7](https://github.com/DataMini/asktable-python/commit/71f15b7d055dafd7aabb993d5ca0f6ca33707620)) +* **client:** correctly parse binary response | stream ([5568773](https://github.com/DataMini/asktable-python/commit/5568773fc1b6ee7a5183cd5e6789ce6eafe119e8)) +* **client:** don't send Content-Type header on GET requests ([41feabc](https://github.com/DataMini/asktable-python/commit/41feabcb23fb5c257d18ba7f96f0ddb9304d53d5)) +* **docs/api:** remove references to nonexistent types ([7d673d4](https://github.com/DataMini/asktable-python/commit/7d673d44b295a507ca08ff0982cc5e033893e3d3)) +* **pagination:** correct next page check ([03552e7](https://github.com/DataMini/asktable-python/commit/03552e74ca1fa48289b48381777b1243398777bc)) +* **parsing:** correctly handle nested discriminated unions ([5fcaeb7](https://github.com/DataMini/asktable-python/commit/5fcaeb76ff37258c12becb7e459a3cfa56988fc0)) +* **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([3036c4b](https://github.com/DataMini/asktable-python/commit/3036c4bdbe59cd13bdfacdd113478e3e6ddd8ca0)) + + +### Chores + +* **ci:** change upload type ([267f707](https://github.com/DataMini/asktable-python/commit/267f707806319c9b4499046f286f891a985d22de)) +* **ci:** enable for pull requests ([a6636e7](https://github.com/DataMini/asktable-python/commit/a6636e7b8409f7750b52c4850f05be437e4ed31d)) +* **ci:** only run for pushes and fork pull requests ([f5756ca](https://github.com/DataMini/asktable-python/commit/f5756ca55464cba7219498f0fcf0786d299fdc7d)) +* **docs:** remove reference to rye shell ([9fc4749](https://github.com/DataMini/asktable-python/commit/9fc4749e8965d398f281078e14f0249d12571ace)) +* **docs:** remove unnecessary param examples ([d2875f3](https://github.com/DataMini/asktable-python/commit/d2875f3438404557c839e0d158a2e573c3607f1f)) +* **internal:** bump pinned h11 dep ([cb54577](https://github.com/DataMini/asktable-python/commit/cb545771166f525600c876d70e6ca9af74aada7f)) +* **internal:** codegen related update ([c281941](https://github.com/DataMini/asktable-python/commit/c28194157b0e93b082fc5c441528a4bdc0640c00)) +* **internal:** codegen related update ([65ea7c5](https://github.com/DataMini/asktable-python/commit/65ea7c536f5fe17dfb13666bf7e37f25bf470bd9)) +* **internal:** update conftest.py ([f06435d](https://github.com/DataMini/asktable-python/commit/f06435ded63522ac7f30d47b560183b86e95ef27)) +* **package:** mark python 3.13 as supported ([e1a20f7](https://github.com/DataMini/asktable-python/commit/e1a20f7a5f7ce9dee0d182c2addc5fcf8b4342ae)) +* **readme:** fix version rendering on pypi ([e05e6e5](https://github.com/DataMini/asktable-python/commit/e05e6e562cfddd5ef7b3ee27a2a155e0e8305e6c)) +* **readme:** update badges ([bc28102](https://github.com/DataMini/asktable-python/commit/bc281028397ea60d93f86ea563e3e9cba303b0c6)) +* **tests:** add tests for httpx client instantiation & proxies ([c620e09](https://github.com/DataMini/asktable-python/commit/c620e09f4be03fabc31167839018e69b8d7f5d7b)) +* **tests:** run tests in parallel ([9d9d65e](https://github.com/DataMini/asktable-python/commit/9d9d65e5be80faba732cd2d29854186ff565b4c7)) +* **tests:** skip some failing tests on the latest python versions ([188abef](https://github.com/DataMini/asktable-python/commit/188abef74adcaf1c5b8b4ee8b39315aba98c7f95)) + + +### Documentation + +* **client:** fix httpx.Timeout documentation reference ([482e328](https://github.com/DataMini/asktable-python/commit/482e328e4938b04c3eca656984857d2ffc302fa3)) + ## 5.4.0 (2025-05-27) Full Changelog: [v5.3.1...v5.4.0](https://github.com/DataMini/asktable-python/compare/v5.3.1...v5.4.0) diff --git a/pyproject.toml b/pyproject.toml index 35db05e5..371a4680 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "asktable" -version = "5.4.0" +version = "5.5.0" description = "The official Python library for the Asktable API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/asktable/_version.py b/src/asktable/_version.py index d445532a..118411d8 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.4.0" # x-release-please-version +__version__ = "5.5.0" # x-release-please-version