From 7ee4e09545e52eaa3d10522709e833b38221ecad Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 23:24:22 +0000 Subject: [PATCH 01/14] chore(internal): version bump (#81) From b41e3bf21e10b11b6d64e15f320cf3d8aa66bfb8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 21:29:05 +0000 Subject: [PATCH 02/14] feat(api): api update (#83) --- src/codex/resources/projects/entries.py | 14 +++++++++++++- src/codex/types/projects/entry.py | 7 +++++++ src/codex/types/projects/entry_create_params.py | 2 ++ src/codex/types/projects/entry_list_params.py | 3 +++ src/codex/types/projects/entry_update_params.py | 2 ++ tests/api_resources/projects/test_entries.py | 6 ++++++ 6 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/codex/resources/projects/entries.py b/src/codex/resources/projects/entries.py index 2fcc8e0b..e2c16547 100644 --- a/src/codex/resources/projects/entries.py +++ b/src/codex/resources/projects/entries.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Optional +from typing import List, Optional from typing_extensions import Literal import httpx @@ -60,6 +60,7 @@ def create( *, question: str, answer: Optional[str] | NotGiven = NOT_GIVEN, + draft_answer: 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, @@ -89,6 +90,7 @@ def create( { "question": question, "answer": answer, + "draft_answer": draft_answer, }, entry_create_params.EntryCreateParams, ), @@ -140,6 +142,7 @@ def update( *, project_id: str, answer: Optional[str] | NotGiven = NOT_GIVEN, + draft_answer: Optional[str] | NotGiven = NOT_GIVEN, frequency_count: Optional[int] | NotGiven = NOT_GIVEN, question: 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. @@ -170,6 +173,7 @@ def update( body=maybe_transform( { "answer": answer, + "draft_answer": draft_answer, "frequency_count": frequency_count, "question": question, }, @@ -190,6 +194,7 @@ def list( offset: int | NotGiven = NOT_GIVEN, order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, sort: Literal["created_at", "answered_at"] | NotGiven = NOT_GIVEN, + states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN, unanswered_only: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -227,6 +232,7 @@ def list( "offset": offset, "order": order, "sort": sort, + "states": states, "unanswered_only": unanswered_only, }, entry_list_params.EntryListParams, @@ -379,6 +385,7 @@ async def create( *, question: str, answer: Optional[str] | NotGiven = NOT_GIVEN, + draft_answer: 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, @@ -408,6 +415,7 @@ async def create( { "question": question, "answer": answer, + "draft_answer": draft_answer, }, entry_create_params.EntryCreateParams, ), @@ -459,6 +467,7 @@ async def update( *, project_id: str, answer: Optional[str] | NotGiven = NOT_GIVEN, + draft_answer: Optional[str] | NotGiven = NOT_GIVEN, frequency_count: Optional[int] | NotGiven = NOT_GIVEN, question: 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. @@ -489,6 +498,7 @@ async def update( body=await async_maybe_transform( { "answer": answer, + "draft_answer": draft_answer, "frequency_count": frequency_count, "question": question, }, @@ -509,6 +519,7 @@ def list( offset: int | NotGiven = NOT_GIVEN, order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, sort: Literal["created_at", "answered_at"] | NotGiven = NOT_GIVEN, + states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN, unanswered_only: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -546,6 +557,7 @@ def list( "offset": offset, "order": order, "sort": sort, + "states": states, "unanswered_only": unanswered_only, }, entry_list_params.EntryListParams, diff --git a/src/codex/types/projects/entry.py b/src/codex/types/projects/entry.py index 4621cc4b..7a2c4502 100644 --- a/src/codex/types/projects/entry.py +++ b/src/codex/types/projects/entry.py @@ -2,6 +2,7 @@ from typing import Optional from datetime import datetime +from typing_extensions import Literal from ..._models import BaseModel @@ -13,10 +14,16 @@ class Entry(BaseModel): question: str + state: Literal["unanswered", "draft", "published", "published_with_draft"] + id: Optional[str] = None answer: Optional[str] = None answered_at: Optional[datetime] = None + draft_answer: Optional[str] = None + + draft_answer_last_edited: Optional[datetime] = None + frequency_count: Optional[int] = None diff --git a/src/codex/types/projects/entry_create_params.py b/src/codex/types/projects/entry_create_params.py index 1ac23dd4..daf30897 100644 --- a/src/codex/types/projects/entry_create_params.py +++ b/src/codex/types/projects/entry_create_params.py @@ -12,3 +12,5 @@ class EntryCreateParams(TypedDict, total=False): question: Required[str] answer: Optional[str] + + draft_answer: Optional[str] diff --git a/src/codex/types/projects/entry_list_params.py b/src/codex/types/projects/entry_list_params.py index b50181f7..605ea482 100644 --- a/src/codex/types/projects/entry_list_params.py +++ b/src/codex/types/projects/entry_list_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import List from typing_extensions import Literal, TypedDict __all__ = ["EntryListParams"] @@ -18,4 +19,6 @@ class EntryListParams(TypedDict, total=False): sort: Literal["created_at", "answered_at"] + states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] + unanswered_only: bool diff --git a/src/codex/types/projects/entry_update_params.py b/src/codex/types/projects/entry_update_params.py index ba105495..05a6332d 100644 --- a/src/codex/types/projects/entry_update_params.py +++ b/src/codex/types/projects/entry_update_params.py @@ -13,6 +13,8 @@ class EntryUpdateParams(TypedDict, total=False): answer: Optional[str] + draft_answer: Optional[str] + frequency_count: Optional[int] question: Optional[str] diff --git a/tests/api_resources/projects/test_entries.py b/tests/api_resources/projects/test_entries.py index 026add46..fbbf6f25 100644 --- a/tests/api_resources/projects/test_entries.py +++ b/tests/api_resources/projects/test_entries.py @@ -36,6 +36,7 @@ def test_method_create_with_all_params(self, client: Codex) -> None: project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", question="question", answer="answer", + draft_answer="draft_answer", ) assert_matches_type(Entry, entry, path=["response"]) @@ -144,6 +145,7 @@ def test_method_update_with_all_params(self, client: Codex) -> None: entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", answer="answer", + draft_answer="draft_answer", frequency_count=0, question="question", ) @@ -210,6 +212,7 @@ def test_method_list_with_all_params(self, client: Codex) -> None: offset=0, order="asc", sort="created_at", + states=["unanswered"], unanswered_only=True, ) assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"]) @@ -412,6 +415,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", question="question", answer="answer", + draft_answer="draft_answer", ) assert_matches_type(Entry, entry, path=["response"]) @@ -520,6 +524,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) -> entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", answer="answer", + draft_answer="draft_answer", frequency_count=0, question="question", ) @@ -586,6 +591,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCodex) -> No offset=0, order="asc", sort="created_at", + states=["unanswered"], unanswered_only=True, ) assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"]) From e4b2929d58b466199bb02e24b8e0a7c9c63f1b3a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 08:05:45 +0000 Subject: [PATCH 03/14] chore(internal): remove extra empty newlines (#84) --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ede43513..d771e49b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,6 @@ Homepage = "https://github.com/cleanlab/codex-python" Repository = "https://github.com/cleanlab/codex-python" - [tool.rye] managed = true # version pins are in requirements-dev.lock @@ -152,7 +151,6 @@ reportImplicitOverride = true reportImportCycles = false reportPrivateUsage = false - [tool.ruff] line-length = 120 output-format = "grouped" From 7e1eaca4c5f2c779b264c34883688b52e1a8602e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 06:29:25 +0000 Subject: [PATCH 04/14] chore(internal): codegen related update (#85) --- requirements-dev.lock | 1 + requirements.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/requirements-dev.lock b/requirements-dev.lock index 1961e8d6..5b7189d6 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -7,6 +7,7 @@ # all-features: true # with-sources: false # generate-hashes: false +# universal: false -e file:. annotated-types==0.6.0 diff --git a/requirements.lock b/requirements.lock index 5d7fff82..1f6c5f7f 100644 --- a/requirements.lock +++ b/requirements.lock @@ -7,6 +7,7 @@ # all-features: true # with-sources: false # generate-hashes: false +# universal: false -e file:. annotated-types==0.6.0 From e026b73fb62aa19689890f14b7dcf355910029a8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 06:32:58 +0000 Subject: [PATCH 05/14] chore(internal): bump rye to 0.44.0 (#86) --- .devcontainer/Dockerfile | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/publish-pypi.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 55d20255..ff261bad 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,7 +3,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} USER vscode -RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.35.0" RYE_INSTALL_OPTION="--yes" bash +RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash ENV PATH=/home/vscode/.rye/shims:$PATH RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e503784c..5ac5f63f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Install dependencies diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 5ed611c7..7c078aa3 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -21,7 +21,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Publish to PyPI From ea6a9422c2a1ff25f14ade1a790ffd943dadbd81 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 06:37:06 +0000 Subject: [PATCH 06/14] fix(types): handle more discriminated union shapes (#87) --- src/codex/_models.py | 7 +++++-- tests/test_models.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/codex/_models.py b/src/codex/_models.py index c4401ff8..b51a1bf5 100644 --- a/src/codex/_models.py +++ b/src/codex/_models.py @@ -65,7 +65,7 @@ from ._constants import RAW_RESPONSE_HEADER if TYPE_CHECKING: - from pydantic_core.core_schema import ModelField, LiteralSchema, ModelFieldsSchema + from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema __all__ = ["BaseModel", "GenericModel"] @@ -646,15 +646,18 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: schema = model.__pydantic_core_schema__ + if schema["type"] == "definitions": + schema = schema["schema"] + if schema["type"] != "model": return None + schema = cast("ModelSchema", schema) fields_schema = schema["schema"] if fields_schema["type"] != "model-fields": return None fields_schema = cast("ModelFieldsSchema", fields_schema) - field = fields_schema["fields"].get(field_name) if not field: return None diff --git a/tests/test_models.py b/tests/test_models.py index 26df341f..73e6d67c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -854,3 +854,35 @@ class Model(BaseModel): m = construct_type(value={"cls": "foo"}, type_=Model) assert isinstance(m, Model) assert isinstance(m.cls, str) + + +def test_discriminated_union_case() -> None: + class A(BaseModel): + type: Literal["a"] + + data: bool + + class B(BaseModel): + type: Literal["b"] + + data: List[Union[A, object]] + + class ModelA(BaseModel): + type: Literal["modelA"] + + data: int + + class ModelB(BaseModel): + type: Literal["modelB"] + + required: str + + data: Union[A, B] + + # when constructing ModelA | ModelB, value data doesn't match ModelB exactly - missing `required` + m = construct_type( + value={"type": "modelB", "data": {"type": "a", "data": True}}, + type_=cast(Any, Annotated[Union[ModelA, ModelB], PropertyInfo(discriminator="type")]), + ) + + assert isinstance(m, ModelB) From 86a40ccd3892d23bb12f78bf5ff13eaa23d8eb2d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:58:10 +0000 Subject: [PATCH 07/14] fix(ci): ensure pip is always available (#88) --- bin/publish-pypi | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/publish-pypi b/bin/publish-pypi index 05bfccbb..ebebf916 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -5,5 +5,6 @@ mkdir -p dist rye build --clean # Patching importlib-metadata version until upstream library version is updated # https://github.com/pypa/twine/issues/977#issuecomment-2189800841 +"$HOME/.rye/self/bin/python3" -m ensurepip "$HOME/.rye/self/bin/python3" -m pip install 'importlib-metadata==7.2.1' rye publish --yes --token=$PYPI_TOKEN From 674c6613c7709c93cca936f086d5348041252972 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 18:05:48 +0000 Subject: [PATCH 08/14] fix(ci): remove publishing patch (#89) --- bin/publish-pypi | 4 ---- pyproject.toml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/bin/publish-pypi b/bin/publish-pypi index ebebf916..826054e9 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -3,8 +3,4 @@ set -eux mkdir -p dist rye build --clean -# Patching importlib-metadata version until upstream library version is updated -# https://github.com/pypa/twine/issues/977#issuecomment-2189800841 -"$HOME/.rye/self/bin/python3" -m ensurepip -"$HOME/.rye/self/bin/python3" -m pip install 'importlib-metadata==7.2.1' rye publish --yes --token=$PYPI_TOKEN diff --git a/pyproject.toml b/pyproject.toml index d771e49b..61f43447 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,7 @@ typecheck = { chain = [ "typecheck:mypy" = "mypy ." [build-system] -requires = ["hatchling", "hatch-fancy-pypi-readme"] +requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"] build-backend = "hatchling.build" [tool.hatch.build] From 52933f2bc708e1f2b5f2e144071a9ee41b27251c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 17:29:08 +0000 Subject: [PATCH 09/14] feat(api): api update (#90) --- src/codex/resources/projects/access_keys.py | 31 +++++++ src/codex/resources/projects/entries.py | 91 +++++++++++++++++++ .../projects/access_key_create_params.py | 8 ++ .../projects/entry_add_question_params.py | 12 ++- .../types/projects/entry_create_params.py | 12 ++- .../types/projects/entry_query_params.py | 12 ++- .../projects/test_access_keys.py | 8 ++ tests/api_resources/projects/test_entries.py | 60 ++++++++++++ 8 files changed, 231 insertions(+), 3 deletions(-) diff --git a/src/codex/resources/projects/access_keys.py b/src/codex/resources/projects/access_keys.py index d375dbca..61987399 100644 --- a/src/codex/resources/projects/access_keys.py +++ b/src/codex/resources/projects/access_keys.py @@ -10,6 +10,7 @@ from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven from ..._utils import ( maybe_transform, + strip_not_given, async_maybe_transform, ) from ..._compat import cached_property @@ -56,6 +57,10 @@ def create( name: str, description: Optional[str] | NotGiven = NOT_GIVEN, expires_at: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + x_client_library_version: str | NotGiven = NOT_GIVEN, + x_integration_type: str | NotGiven = NOT_GIVEN, + x_source: str | NotGiven = NOT_GIVEN, + x_stainless_package_version: 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, @@ -77,6 +82,17 @@ def create( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + extra_headers = { + **strip_not_given( + { + "x-client-library-version": x_client_library_version, + "x-integration-type": x_integration_type, + "x-source": x_source, + "x-stainless-package-version": x_stainless_package_version, + } + ), + **(extra_headers or {}), + } return self._post( f"/api/projects/{project_id}/access_keys/", body=maybe_transform( @@ -330,6 +346,10 @@ async def create( name: str, description: Optional[str] | NotGiven = NOT_GIVEN, expires_at: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + x_client_library_version: str | NotGiven = NOT_GIVEN, + x_integration_type: str | NotGiven = NOT_GIVEN, + x_source: str | NotGiven = NOT_GIVEN, + x_stainless_package_version: 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, @@ -351,6 +371,17 @@ async def create( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + extra_headers = { + **strip_not_given( + { + "x-client-library-version": x_client_library_version, + "x-integration-type": x_integration_type, + "x-source": x_source, + "x-stainless-package-version": x_stainless_package_version, + } + ), + **(extra_headers or {}), + } return await self._post( f"/api/projects/{project_id}/access_keys/", body=await async_maybe_transform( diff --git a/src/codex/resources/projects/entries.py b/src/codex/resources/projects/entries.py index e2c16547..f5eebad6 100644 --- a/src/codex/resources/projects/entries.py +++ b/src/codex/resources/projects/entries.py @@ -10,6 +10,7 @@ from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven from ..._utils import ( maybe_transform, + strip_not_given, async_maybe_transform, ) from ..._compat import cached_property @@ -61,6 +62,10 @@ def create( question: str, answer: Optional[str] | NotGiven = NOT_GIVEN, draft_answer: Optional[str] | NotGiven = NOT_GIVEN, + x_client_library_version: str | NotGiven = NOT_GIVEN, + x_integration_type: str | NotGiven = NOT_GIVEN, + x_source: str | NotGiven = NOT_GIVEN, + x_stainless_package_version: 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, @@ -84,6 +89,17 @@ def create( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + extra_headers = { + **strip_not_given( + { + "x-client-library-version": x_client_library_version, + "x-integration-type": x_integration_type, + "x-source": x_source, + "x-stainless-package-version": x_stainless_package_version, + } + ), + **(extra_headers or {}), + } return self._post( f"/api/projects/{project_id}/entries/", body=maybe_transform( @@ -283,6 +299,10 @@ def add_question( project_id: str, *, question: str, + x_client_library_version: str | NotGiven = NOT_GIVEN, + x_integration_type: str | NotGiven = NOT_GIVEN, + x_source: str | NotGiven = NOT_GIVEN, + x_stainless_package_version: 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, @@ -307,6 +327,17 @@ def add_question( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + extra_headers = { + **strip_not_given( + { + "x-client-library-version": x_client_library_version, + "x-integration-type": x_integration_type, + "x-source": x_source, + "x-stainless-package-version": x_stainless_package_version, + } + ), + **(extra_headers or {}), + } return self._post( f"/api/projects/{project_id}/entries/add_question", body=maybe_transform({"question": question}, entry_add_question_params.EntryAddQuestionParams), @@ -321,6 +352,10 @@ def query( project_id: str, *, question: str, + x_client_library_version: str | NotGiven = NOT_GIVEN, + x_integration_type: str | NotGiven = NOT_GIVEN, + x_source: str | NotGiven = NOT_GIVEN, + x_stainless_package_version: 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, @@ -349,6 +384,17 @@ def query( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + extra_headers = { + **strip_not_given( + { + "x-client-library-version": x_client_library_version, + "x-integration-type": x_integration_type, + "x-source": x_source, + "x-stainless-package-version": x_stainless_package_version, + } + ), + **(extra_headers or {}), + } return self._post( f"/api/projects/{project_id}/entries/query", body=maybe_transform({"question": question}, entry_query_params.EntryQueryParams), @@ -386,6 +432,10 @@ async def create( question: str, answer: Optional[str] | NotGiven = NOT_GIVEN, draft_answer: Optional[str] | NotGiven = NOT_GIVEN, + x_client_library_version: str | NotGiven = NOT_GIVEN, + x_integration_type: str | NotGiven = NOT_GIVEN, + x_source: str | NotGiven = NOT_GIVEN, + x_stainless_package_version: 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, @@ -409,6 +459,17 @@ async def create( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + extra_headers = { + **strip_not_given( + { + "x-client-library-version": x_client_library_version, + "x-integration-type": x_integration_type, + "x-source": x_source, + "x-stainless-package-version": x_stainless_package_version, + } + ), + **(extra_headers or {}), + } return await self._post( f"/api/projects/{project_id}/entries/", body=await async_maybe_transform( @@ -608,6 +669,10 @@ async def add_question( project_id: str, *, question: str, + x_client_library_version: str | NotGiven = NOT_GIVEN, + x_integration_type: str | NotGiven = NOT_GIVEN, + x_source: str | NotGiven = NOT_GIVEN, + x_stainless_package_version: 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, @@ -632,6 +697,17 @@ async def add_question( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + extra_headers = { + **strip_not_given( + { + "x-client-library-version": x_client_library_version, + "x-integration-type": x_integration_type, + "x-source": x_source, + "x-stainless-package-version": x_stainless_package_version, + } + ), + **(extra_headers or {}), + } return await self._post( f"/api/projects/{project_id}/entries/add_question", body=await async_maybe_transform({"question": question}, entry_add_question_params.EntryAddQuestionParams), @@ -646,6 +722,10 @@ async def query( project_id: str, *, question: str, + x_client_library_version: str | NotGiven = NOT_GIVEN, + x_integration_type: str | NotGiven = NOT_GIVEN, + x_source: str | NotGiven = NOT_GIVEN, + x_stainless_package_version: 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, @@ -674,6 +754,17 @@ async def query( """ if not project_id: raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + extra_headers = { + **strip_not_given( + { + "x-client-library-version": x_client_library_version, + "x-integration-type": x_integration_type, + "x-source": x_source, + "x-stainless-package-version": x_stainless_package_version, + } + ), + **(extra_headers or {}), + } return await self._post( f"/api/projects/{project_id}/entries/query", body=await async_maybe_transform({"question": question}, entry_query_params.EntryQueryParams), diff --git a/src/codex/types/projects/access_key_create_params.py b/src/codex/types/projects/access_key_create_params.py index 1cbc202f..cf5f00fb 100644 --- a/src/codex/types/projects/access_key_create_params.py +++ b/src/codex/types/projects/access_key_create_params.py @@ -17,3 +17,11 @@ class AccessKeyCreateParams(TypedDict, total=False): description: Optional[str] expires_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + + x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")] + + x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")] + + x_source: Annotated[str, PropertyInfo(alias="x-source")] + + x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")] diff --git a/src/codex/types/projects/entry_add_question_params.py b/src/codex/types/projects/entry_add_question_params.py index e2d009b4..b310f96b 100644 --- a/src/codex/types/projects/entry_add_question_params.py +++ b/src/codex/types/projects/entry_add_question_params.py @@ -2,10 +2,20 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo __all__ = ["EntryAddQuestionParams"] class EntryAddQuestionParams(TypedDict, total=False): question: Required[str] + + x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")] + + x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")] + + x_source: Annotated[str, PropertyInfo(alias="x-source")] + + x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")] diff --git a/src/codex/types/projects/entry_create_params.py b/src/codex/types/projects/entry_create_params.py index daf30897..0022942f 100644 --- a/src/codex/types/projects/entry_create_params.py +++ b/src/codex/types/projects/entry_create_params.py @@ -3,7 +3,9 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo __all__ = ["EntryCreateParams"] @@ -14,3 +16,11 @@ class EntryCreateParams(TypedDict, total=False): answer: Optional[str] draft_answer: Optional[str] + + x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")] + + x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")] + + x_source: Annotated[str, PropertyInfo(alias="x-source")] + + x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")] diff --git a/src/codex/types/projects/entry_query_params.py b/src/codex/types/projects/entry_query_params.py index b6fbc437..bc0e317c 100644 --- a/src/codex/types/projects/entry_query_params.py +++ b/src/codex/types/projects/entry_query_params.py @@ -2,10 +2,20 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo __all__ = ["EntryQueryParams"] class EntryQueryParams(TypedDict, total=False): question: Required[str] + + x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")] + + x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")] + + x_source: Annotated[str, PropertyInfo(alias="x-source")] + + x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")] diff --git a/tests/api_resources/projects/test_access_keys.py b/tests/api_resources/projects/test_access_keys.py index 240c31e1..ad4ee5e4 100644 --- a/tests/api_resources/projects/test_access_keys.py +++ b/tests/api_resources/projects/test_access_keys.py @@ -39,6 +39,10 @@ def test_method_create_with_all_params(self, client: Codex) -> None: name="name", description="description", expires_at=parse_datetime("2019-12-27T18:11:19.117Z"), + x_client_library_version="x-client-library-version", + x_integration_type="x-integration-type", + x_source="x-source", + x_stainless_package_version="x-stainless-package-version", ) assert_matches_type(AccessKeySchema, access_key, path=["response"]) @@ -395,6 +399,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> name="name", description="description", expires_at=parse_datetime("2019-12-27T18:11:19.117Z"), + x_client_library_version="x-client-library-version", + x_integration_type="x-integration-type", + x_source="x-source", + x_stainless_package_version="x-stainless-package-version", ) assert_matches_type(AccessKeySchema, access_key, path=["response"]) diff --git a/tests/api_resources/projects/test_entries.py b/tests/api_resources/projects/test_entries.py index fbbf6f25..8a18dc01 100644 --- a/tests/api_resources/projects/test_entries.py +++ b/tests/api_resources/projects/test_entries.py @@ -37,6 +37,10 @@ def test_method_create_with_all_params(self, client: Codex) -> None: question="question", answer="answer", draft_answer="draft_answer", + x_client_library_version="x-client-library-version", + x_integration_type="x-integration-type", + x_source="x-source", + x_stainless_package_version="x-stainless-package-version", ) assert_matches_type(Entry, entry, path=["response"]) @@ -312,6 +316,19 @@ def test_method_add_question(self, client: Codex) -> None: ) assert_matches_type(Entry, entry, path=["response"]) + @pytest.mark.skip() + @parametrize + def test_method_add_question_with_all_params(self, client: Codex) -> None: + entry = client.projects.entries.add_question( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + question="question", + x_client_library_version="x-client-library-version", + x_integration_type="x-integration-type", + x_source="x-source", + x_stainless_package_version="x-stainless-package-version", + ) + assert_matches_type(Entry, entry, path=["response"]) + @pytest.mark.skip() @parametrize def test_raw_response_add_question(self, client: Codex) -> None: @@ -358,6 +375,19 @@ def test_method_query(self, client: Codex) -> None: ) assert_matches_type(Optional[Entry], entry, path=["response"]) + @pytest.mark.skip() + @parametrize + def test_method_query_with_all_params(self, client: Codex) -> None: + entry = client.projects.entries.query( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + question="question", + x_client_library_version="x-client-library-version", + x_integration_type="x-integration-type", + x_source="x-source", + x_stainless_package_version="x-stainless-package-version", + ) + assert_matches_type(Optional[Entry], entry, path=["response"]) + @pytest.mark.skip() @parametrize def test_raw_response_query(self, client: Codex) -> None: @@ -416,6 +446,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> question="question", answer="answer", draft_answer="draft_answer", + x_client_library_version="x-client-library-version", + x_integration_type="x-integration-type", + x_source="x-source", + x_stainless_package_version="x-stainless-package-version", ) assert_matches_type(Entry, entry, path=["response"]) @@ -691,6 +725,19 @@ async def test_method_add_question(self, async_client: AsyncCodex) -> None: ) assert_matches_type(Entry, entry, path=["response"]) + @pytest.mark.skip() + @parametrize + async def test_method_add_question_with_all_params(self, async_client: AsyncCodex) -> None: + entry = await async_client.projects.entries.add_question( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + question="question", + x_client_library_version="x-client-library-version", + x_integration_type="x-integration-type", + x_source="x-source", + x_stainless_package_version="x-stainless-package-version", + ) + assert_matches_type(Entry, entry, path=["response"]) + @pytest.mark.skip() @parametrize async def test_raw_response_add_question(self, async_client: AsyncCodex) -> None: @@ -737,6 +784,19 @@ async def test_method_query(self, async_client: AsyncCodex) -> None: ) assert_matches_type(Optional[Entry], entry, path=["response"]) + @pytest.mark.skip() + @parametrize + async def test_method_query_with_all_params(self, async_client: AsyncCodex) -> None: + entry = await async_client.projects.entries.query( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + question="question", + x_client_library_version="x-client-library-version", + x_integration_type="x-integration-type", + x_source="x-source", + x_stainless_package_version="x-stainless-package-version", + ) + assert_matches_type(Optional[Entry], entry, path=["response"]) + @pytest.mark.skip() @parametrize async def test_raw_response_query(self, async_client: AsyncCodex) -> None: From 6b97689646d7b3611ace81c630fafa1962b5c94d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 05:25:22 +0000 Subject: [PATCH 10/14] chore: fix typos (#91) --- src/codex/_models.py | 2 +- src/codex/_utils/_transform.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codex/_models.py b/src/codex/_models.py index b51a1bf5..34935716 100644 --- a/src/codex/_models.py +++ b/src/codex/_models.py @@ -681,7 +681,7 @@ def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: setattr(typ, "__pydantic_config__", config) # noqa: B010 -# our use of subclasssing here causes weirdness for type checkers, +# our use of subclassing here causes weirdness for type checkers, # so we just pretend that we don't subclass if TYPE_CHECKING: GenericModel = BaseModel diff --git a/src/codex/_utils/_transform.py b/src/codex/_utils/_transform.py index 18afd9d8..7ac2e17f 100644 --- a/src/codex/_utils/_transform.py +++ b/src/codex/_utils/_transform.py @@ -126,7 +126,7 @@ def _get_annotated_type(type_: type) -> type | None: def _maybe_transform_key(key: str, type_: type) -> str: """Transform the given `data` based on the annotations provided in `type_`. - Note: this function only looks at `Annotated` types that contain `PropertInfo` metadata. + Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. """ annotated_type = _get_annotated_type(type_) if annotated_type is None: From c32a0ad259c79661a55ba563bd50ea1a6b590de5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 05:26:03 +0000 Subject: [PATCH 11/14] codegen metadata --- .stats.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.stats.yml b/.stats.yml index 7982133f..d526653e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1,3 @@ configured_endpoints: 37 +openapi_spec_hash: c2648fabb12e6096d5f7a3ab78300d66 +config_hash: 0529917e0e61d8cd6366481b77eff77e From f22253d7ed83003b8ff9652b7d2f16e8bd744a54 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 21:28:44 +0000 Subject: [PATCH 12/14] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index d526653e..893f8fab 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,3 +1,3 @@ configured_endpoints: 37 -openapi_spec_hash: c2648fabb12e6096d5f7a3ab78300d66 +openapi_spec_hash: 6993cffe14e021af26bf142f5b557263 config_hash: 0529917e0e61d8cd6366481b77eff77e From 14da02311e598a1d5f4e41a100160b81befd4f61 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 21:15:22 +0000 Subject: [PATCH 13/14] feat(api): updates from question grouping (#93) --- .stats.yml | 6 +- api.md | 20 +- src/codex/pagination.py | 62 ++++ src/codex/resources/health.py | 50 --- src/codex/resources/projects/__init__.py | 14 + src/codex/resources/projects/clusters.py | 296 +++++++++++++++++ src/codex/resources/projects/entries.py | 299 +----------------- src/codex/resources/projects/projects.py | 32 ++ src/codex/types/projects/__init__.py | 6 +- ..._list_params.py => cluster_list_params.py} | 10 +- .../types/projects/cluster_list_response.py | 36 +++ .../cluster_list_variants_response.py | 14 + src/codex/types/projects/entry.py | 8 +- .../projects/entry_add_question_params.py | 21 -- .../types/projects/entry_query_response.py | 23 ++ .../types/projects/entry_update_params.py | 2 - tests/api_resources/projects/test_clusters.py | 241 ++++++++++++++ tests/api_resources/projects/test_entries.py | 257 +-------------- tests/api_resources/test_health.py | 56 ---- 19 files changed, 771 insertions(+), 682 deletions(-) create mode 100644 src/codex/resources/projects/clusters.py rename src/codex/types/projects/{entry_list_params.py => cluster_list_params.py} (66%) create mode 100644 src/codex/types/projects/cluster_list_response.py create mode 100644 src/codex/types/projects/cluster_list_variants_response.py delete mode 100644 src/codex/types/projects/entry_add_question_params.py create mode 100644 src/codex/types/projects/entry_query_response.py create mode 100644 tests/api_resources/projects/test_clusters.py diff --git a/.stats.yml b/.stats.yml index 893f8fab..d2d3f6a5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,3 +1,3 @@ -configured_endpoints: 37 -openapi_spec_hash: 6993cffe14e021af26bf142f5b557263 -config_hash: 0529917e0e61d8cd6366481b77eff77e +configured_endpoints: 36 +openapi_spec_hash: 4e7cb2cd6132c29f60a87a958f617a41 +config_hash: adbedb6317fca6f566f54564cc341846 diff --git a/api.md b/api.md index 5e258334..b241c15c 100644 --- a/api.md +++ b/api.md @@ -10,7 +10,6 @@ Methods: - client.health.check() -> HealthCheckResponse - client.health.db() -> HealthCheckResponse -- client.health.weaviate() -> HealthCheckResponse # Organizations @@ -175,7 +174,7 @@ Methods: Types: ```python -from codex.types.projects import Entry +from codex.types.projects import Entry, EntryQueryResponse ``` Methods: @@ -183,10 +182,21 @@ Methods: - client.projects.entries.create(project_id, \*\*params) -> Entry - client.projects.entries.retrieve(entry_id, \*, project_id) -> Entry - client.projects.entries.update(entry_id, \*, project_id, \*\*params) -> Entry -- client.projects.entries.list(project_id, \*\*params) -> SyncOffsetPageEntries[Entry] - client.projects.entries.delete(entry_id, \*, project_id) -> None -- client.projects.entries.add_question(project_id, \*\*params) -> Entry -- client.projects.entries.query(project_id, \*\*params) -> Optional[Entry] +- client.projects.entries.query(project_id, \*\*params) -> EntryQueryResponse + +## Clusters + +Types: + +```python +from codex.types.projects import ClusterListResponse, ClusterListVariantsResponse +``` + +Methods: + +- client.projects.clusters.list(project_id, \*\*params) -> SyncOffsetPageClusters[ClusterListResponse] +- client.projects.clusters.list_variants(representative_entry_id, \*, project_id) -> ClusterListVariantsResponse # Tlm diff --git a/src/codex/pagination.py b/src/codex/pagination.py index 48ed5018..1f590df5 100644 --- a/src/codex/pagination.py +++ b/src/codex/pagination.py @@ -12,6 +12,8 @@ __all__ = [ "SyncMyOffsetPageTopLevelArray", "AsyncMyOffsetPageTopLevelArray", + "SyncOffsetPageClusters", + "AsyncOffsetPageClusters", "SyncOffsetPageEntries", "AsyncOffsetPageEntries", ] @@ -83,6 +85,66 @@ def build(cls: Type[_BaseModelT], *, response: Response, data: object) -> _BaseM ) +class SyncOffsetPageClusters(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + clusters: List[_T] + total_count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + clusters = self.clusters + if not clusters: + return [] + return clusters + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + total_count = self.total_count + if total_count is None: + return None + + if current_count < total_count: + return PageInfo(params={"offset": current_count}) + + return None + + +class AsyncOffsetPageClusters(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + clusters: List[_T] + total_count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + clusters = self.clusters + if not clusters: + return [] + return clusters + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + total_count = self.total_count + if total_count is None: + return None + + if current_count < total_count: + return PageInfo(params={"offset": current_count}) + + return None + + class SyncOffsetPageEntries(BaseSyncPage[_T], BasePage[_T], Generic[_T]): entries: List[_T] total_count: Optional[int] = None diff --git a/src/codex/resources/health.py b/src/codex/resources/health.py index 6a777c63..d74d23a5 100644 --- a/src/codex/resources/health.py +++ b/src/codex/resources/health.py @@ -77,25 +77,6 @@ def db( cast_to=HealthCheckResponse, ) - def weaviate( - 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, - ) -> HealthCheckResponse: - """Check the weaviate connection.""" - return self._get( - "/api/health/weaviate", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=HealthCheckResponse, - ) - class AsyncHealthResource(AsyncAPIResource): @cached_property @@ -155,25 +136,6 @@ async def db( cast_to=HealthCheckResponse, ) - async def weaviate( - 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, - ) -> HealthCheckResponse: - """Check the weaviate connection.""" - return await self._get( - "/api/health/weaviate", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=HealthCheckResponse, - ) - class HealthResourceWithRawResponse: def __init__(self, health: HealthResource) -> None: @@ -185,9 +147,6 @@ def __init__(self, health: HealthResource) -> None: self.db = to_raw_response_wrapper( health.db, ) - self.weaviate = to_raw_response_wrapper( - health.weaviate, - ) class AsyncHealthResourceWithRawResponse: @@ -200,9 +159,6 @@ def __init__(self, health: AsyncHealthResource) -> None: self.db = async_to_raw_response_wrapper( health.db, ) - self.weaviate = async_to_raw_response_wrapper( - health.weaviate, - ) class HealthResourceWithStreamingResponse: @@ -215,9 +171,6 @@ def __init__(self, health: HealthResource) -> None: self.db = to_streamed_response_wrapper( health.db, ) - self.weaviate = to_streamed_response_wrapper( - health.weaviate, - ) class AsyncHealthResourceWithStreamingResponse: @@ -230,6 +183,3 @@ def __init__(self, health: AsyncHealthResource) -> None: self.db = async_to_streamed_response_wrapper( health.db, ) - self.weaviate = async_to_streamed_response_wrapper( - health.weaviate, - ) diff --git a/src/codex/resources/projects/__init__.py b/src/codex/resources/projects/__init__.py index 01599858..2c0595d2 100644 --- a/src/codex/resources/projects/__init__.py +++ b/src/codex/resources/projects/__init__.py @@ -8,6 +8,14 @@ EntriesResourceWithStreamingResponse, AsyncEntriesResourceWithStreamingResponse, ) +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) from .projects import ( ProjectsResource, AsyncProjectsResource, @@ -38,6 +46,12 @@ "AsyncEntriesResourceWithRawResponse", "EntriesResourceWithStreamingResponse", "AsyncEntriesResourceWithStreamingResponse", + "ClustersResource", + "AsyncClustersResource", + "ClustersResourceWithRawResponse", + "AsyncClustersResourceWithRawResponse", + "ClustersResourceWithStreamingResponse", + "AsyncClustersResourceWithStreamingResponse", "ProjectsResource", "AsyncProjectsResource", "ProjectsResourceWithRawResponse", diff --git a/src/codex/resources/projects/clusters.py b/src/codex/resources/projects/clusters.py new file mode 100644 index 00000000..54b6c4c3 --- /dev/null +++ b/src/codex/resources/projects/clusters.py @@ -0,0 +1,296 @@ +# 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 Literal + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPageClusters, AsyncOffsetPageClusters +from ..._base_client import AsyncPaginator, make_request_options +from ...types.projects import cluster_list_params +from ...types.projects.cluster_list_response import ClusterListResponse +from ...types.projects.cluster_list_variants_response import ClusterListVariantsResponse + +__all__ = ["ClustersResource", "AsyncClustersResource"] + + +class ClustersResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ClustersResourceWithRawResponse: + """ + 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/cleanlab/codex-python#accessing-raw-response-data-eg-headers + """ + return ClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cleanlab/codex-python#with_streaming_response + """ + return ClustersResourceWithStreamingResponse(self) + + def list( + self, + project_id: str, + *, + limit: int | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + sort: Literal["created_at", "answered_at", "cluster_frequency_count"] | NotGiven = NOT_GIVEN, + states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | 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, + ) -> SyncOffsetPageClusters[ClusterListResponse]: + """ + List knowledge entries for a 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._get_api_list( + f"/api/projects/{project_id}/entries/clusters", + page=SyncOffsetPageClusters[ClusterListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "order": order, + "sort": sort, + "states": states, + }, + cluster_list_params.ClusterListParams, + ), + ), + model=ClusterListResponse, + ) + + def list_variants( + self, + representative_entry_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ClusterListVariantsResponse: + """ + Get Cluster Variants Route + + 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}") + if not representative_entry_id: + raise ValueError( + f"Expected a non-empty value for `representative_entry_id` but received {representative_entry_id!r}" + ) + return self._get( + f"/api/projects/{project_id}/entries/clusters/{representative_entry_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClusterListVariantsResponse, + ) + + +class AsyncClustersResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncClustersResourceWithRawResponse: + """ + 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/cleanlab/codex-python#accessing-raw-response-data-eg-headers + """ + return AsyncClustersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncClustersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cleanlab/codex-python#with_streaming_response + """ + return AsyncClustersResourceWithStreamingResponse(self) + + def list( + self, + project_id: str, + *, + limit: int | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + sort: Literal["created_at", "answered_at", "cluster_frequency_count"] | NotGiven = NOT_GIVEN, + states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | 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[ClusterListResponse, AsyncOffsetPageClusters[ClusterListResponse]]: + """ + List knowledge entries for a 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._get_api_list( + f"/api/projects/{project_id}/entries/clusters", + page=AsyncOffsetPageClusters[ClusterListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + "order": order, + "sort": sort, + "states": states, + }, + cluster_list_params.ClusterListParams, + ), + ), + model=ClusterListResponse, + ) + + async def list_variants( + self, + representative_entry_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ClusterListVariantsResponse: + """ + Get Cluster Variants Route + + 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}") + if not representative_entry_id: + raise ValueError( + f"Expected a non-empty value for `representative_entry_id` but received {representative_entry_id!r}" + ) + return await self._get( + f"/api/projects/{project_id}/entries/clusters/{representative_entry_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClusterListVariantsResponse, + ) + + +class ClustersResourceWithRawResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.list = to_raw_response_wrapper( + clusters.list, + ) + self.list_variants = to_raw_response_wrapper( + clusters.list_variants, + ) + + +class AsyncClustersResourceWithRawResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.list = async_to_raw_response_wrapper( + clusters.list, + ) + self.list_variants = async_to_raw_response_wrapper( + clusters.list_variants, + ) + + +class ClustersResourceWithStreamingResponse: + def __init__(self, clusters: ClustersResource) -> None: + self._clusters = clusters + + self.list = to_streamed_response_wrapper( + clusters.list, + ) + self.list_variants = to_streamed_response_wrapper( + clusters.list_variants, + ) + + +class AsyncClustersResourceWithStreamingResponse: + def __init__(self, clusters: AsyncClustersResource) -> None: + self._clusters = clusters + + self.list = async_to_streamed_response_wrapper( + clusters.list, + ) + self.list_variants = async_to_streamed_response_wrapper( + clusters.list_variants, + ) diff --git a/src/codex/resources/projects/entries.py b/src/codex/resources/projects/entries.py index f5eebad6..8be96b06 100644 --- a/src/codex/resources/projects/entries.py +++ b/src/codex/resources/projects/entries.py @@ -2,8 +2,7 @@ from __future__ import annotations -from typing import List, Optional -from typing_extensions import Literal +from typing import Optional import httpx @@ -21,16 +20,10 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ...pagination import SyncOffsetPageEntries, AsyncOffsetPageEntries -from ..._base_client import AsyncPaginator, make_request_options -from ...types.projects import ( - entry_list_params, - entry_query_params, - entry_create_params, - entry_update_params, - entry_add_question_params, -) +from ..._base_client import make_request_options +from ...types.projects import entry_query_params, entry_create_params, entry_update_params from ...types.projects.entry import Entry +from ...types.projects.entry_query_response import EntryQueryResponse __all__ = ["EntriesResource", "AsyncEntriesResource"] @@ -74,9 +67,7 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Entry: """ - Create a knowledge entry for a project. - - Raises: HTTPException: If an existing entry is found with the same question. + Create a new knowledge entry for a project. Args: extra_headers: Send extra headers @@ -159,7 +150,6 @@ def update( project_id: str, answer: Optional[str] | NotGiven = NOT_GIVEN, draft_answer: Optional[str] | NotGiven = NOT_GIVEN, - frequency_count: Optional[int] | NotGiven = NOT_GIVEN, question: 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. @@ -190,7 +180,6 @@ def update( { "answer": answer, "draft_answer": draft_answer, - "frequency_count": frequency_count, "question": question, }, entry_update_params.EntryUpdateParams, @@ -201,62 +190,6 @@ def update( cast_to=Entry, ) - def list( - self, - project_id: str, - *, - answered_only: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - offset: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - sort: Literal["created_at", "answered_at"] | NotGiven = NOT_GIVEN, - states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN, - unanswered_only: bool | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncOffsetPageEntries[Entry]: - """ - List knowledge entries for a 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._get_api_list( - f"/api/projects/{project_id}/entries/", - page=SyncOffsetPageEntries[Entry], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "answered_only": answered_only, - "limit": limit, - "offset": offset, - "order": order, - "sort": sort, - "states": states, - "unanswered_only": unanswered_only, - }, - entry_list_params.EntryListParams, - ), - ), - model=Entry, - ) - def delete( self, entry_id: str, @@ -294,59 +227,6 @@ def delete( cast_to=NoneType, ) - def add_question( - self, - project_id: str, - *, - question: str, - x_client_library_version: str | NotGiven = NOT_GIVEN, - x_integration_type: str | NotGiven = NOT_GIVEN, - x_source: str | NotGiven = NOT_GIVEN, - x_stainless_package_version: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Entry: - """ - Add a question to a project. - - Returns: 201 Created if a new question was added 200 OK if the question already - existed - - 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}") - extra_headers = { - **strip_not_given( - { - "x-client-library-version": x_client_library_version, - "x-integration-type": x_integration_type, - "x-source": x_source, - "x-stainless-package-version": x_stainless_package_version, - } - ), - **(extra_headers or {}), - } - return self._post( - f"/api/projects/{project_id}/entries/add_question", - body=maybe_transform({"question": question}, entry_add_question_params.EntryAddQuestionParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Entry, - ) - def query( self, project_id: str, @@ -362,16 +242,9 @@ def query( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Optional[Entry]: - """Query knowledge for a project. - - Also increments the frequency_count for the - matching entry if found. - - Returns the matching entry if found and answered, otherwise returns None. This - allows the client to distinguish between: (1) no matching question found - (returns None), and (2) matching question found but not yet answered (returns - Entry with answer=None). + ) -> EntryQueryResponse: + """ + Query Entries Route Args: extra_headers: Send extra headers @@ -401,7 +274,7 @@ def query( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Entry, + cast_to=EntryQueryResponse, ) @@ -444,9 +317,7 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Entry: """ - Create a knowledge entry for a project. - - Raises: HTTPException: If an existing entry is found with the same question. + Create a new knowledge entry for a project. Args: extra_headers: Send extra headers @@ -529,7 +400,6 @@ async def update( project_id: str, answer: Optional[str] | NotGiven = NOT_GIVEN, draft_answer: Optional[str] | NotGiven = NOT_GIVEN, - frequency_count: Optional[int] | NotGiven = NOT_GIVEN, question: 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. @@ -560,7 +430,6 @@ async def update( { "answer": answer, "draft_answer": draft_answer, - "frequency_count": frequency_count, "question": question, }, entry_update_params.EntryUpdateParams, @@ -571,62 +440,6 @@ async def update( cast_to=Entry, ) - def list( - self, - project_id: str, - *, - answered_only: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - offset: int | NotGiven = NOT_GIVEN, - order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - sort: Literal["created_at", "answered_at"] | NotGiven = NOT_GIVEN, - states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] | NotGiven = NOT_GIVEN, - unanswered_only: bool | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[Entry, AsyncOffsetPageEntries[Entry]]: - """ - List knowledge entries for a 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._get_api_list( - f"/api/projects/{project_id}/entries/", - page=AsyncOffsetPageEntries[Entry], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "answered_only": answered_only, - "limit": limit, - "offset": offset, - "order": order, - "sort": sort, - "states": states, - "unanswered_only": unanswered_only, - }, - entry_list_params.EntryListParams, - ), - ), - model=Entry, - ) - async def delete( self, entry_id: str, @@ -664,59 +477,6 @@ async def delete( cast_to=NoneType, ) - async def add_question( - self, - project_id: str, - *, - question: str, - x_client_library_version: str | NotGiven = NOT_GIVEN, - x_integration_type: str | NotGiven = NOT_GIVEN, - x_source: str | NotGiven = NOT_GIVEN, - x_stainless_package_version: str | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Entry: - """ - Add a question to a project. - - Returns: 201 Created if a new question was added 200 OK if the question already - existed - - 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}") - extra_headers = { - **strip_not_given( - { - "x-client-library-version": x_client_library_version, - "x-integration-type": x_integration_type, - "x-source": x_source, - "x-stainless-package-version": x_stainless_package_version, - } - ), - **(extra_headers or {}), - } - return await self._post( - f"/api/projects/{project_id}/entries/add_question", - body=await async_maybe_transform({"question": question}, entry_add_question_params.EntryAddQuestionParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Entry, - ) - async def query( self, project_id: str, @@ -732,16 +492,9 @@ async def query( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> Optional[Entry]: - """Query knowledge for a project. - - Also increments the frequency_count for the - matching entry if found. - - Returns the matching entry if found and answered, otherwise returns None. This - allows the client to distinguish between: (1) no matching question found - (returns None), and (2) matching question found but not yet answered (returns - Entry with answer=None). + ) -> EntryQueryResponse: + """ + Query Entries Route Args: extra_headers: Send extra headers @@ -771,7 +524,7 @@ async def query( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Entry, + cast_to=EntryQueryResponse, ) @@ -788,15 +541,9 @@ def __init__(self, entries: EntriesResource) -> None: self.update = to_raw_response_wrapper( entries.update, ) - self.list = to_raw_response_wrapper( - entries.list, - ) self.delete = to_raw_response_wrapper( entries.delete, ) - self.add_question = to_raw_response_wrapper( - entries.add_question, - ) self.query = to_raw_response_wrapper( entries.query, ) @@ -815,15 +562,9 @@ def __init__(self, entries: AsyncEntriesResource) -> None: self.update = async_to_raw_response_wrapper( entries.update, ) - self.list = async_to_raw_response_wrapper( - entries.list, - ) self.delete = async_to_raw_response_wrapper( entries.delete, ) - self.add_question = async_to_raw_response_wrapper( - entries.add_question, - ) self.query = async_to_raw_response_wrapper( entries.query, ) @@ -842,15 +583,9 @@ def __init__(self, entries: EntriesResource) -> None: self.update = to_streamed_response_wrapper( entries.update, ) - self.list = to_streamed_response_wrapper( - entries.list, - ) self.delete = to_streamed_response_wrapper( entries.delete, ) - self.add_question = to_streamed_response_wrapper( - entries.add_question, - ) self.query = to_streamed_response_wrapper( entries.query, ) @@ -869,15 +604,9 @@ def __init__(self, entries: AsyncEntriesResource) -> None: self.update = async_to_streamed_response_wrapper( entries.update, ) - self.list = async_to_streamed_response_wrapper( - entries.list, - ) self.delete = async_to_streamed_response_wrapper( entries.delete, ) - self.add_question = async_to_streamed_response_wrapper( - entries.add_question, - ) self.query = async_to_streamed_response_wrapper( entries.query, ) diff --git a/src/codex/resources/projects/projects.py b/src/codex/resources/projects/projects.py index 38d7b036..8a7ff1b3 100644 --- a/src/codex/resources/projects/projects.py +++ b/src/codex/resources/projects/projects.py @@ -21,6 +21,14 @@ maybe_transform, async_maybe_transform, ) +from .clusters import ( + ClustersResource, + AsyncClustersResource, + ClustersResourceWithRawResponse, + AsyncClustersResourceWithRawResponse, + ClustersResourceWithStreamingResponse, + AsyncClustersResourceWithStreamingResponse, +) from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -53,6 +61,10 @@ def access_keys(self) -> AccessKeysResource: def entries(self) -> EntriesResource: return EntriesResource(self._client) + @cached_property + def clusters(self) -> ClustersResource: + return ClustersResource(self._client) + @cached_property def with_raw_response(self) -> ProjectsResourceWithRawResponse: """ @@ -321,6 +333,10 @@ def access_keys(self) -> AsyncAccessKeysResource: def entries(self) -> AsyncEntriesResource: return AsyncEntriesResource(self._client) + @cached_property + def clusters(self) -> AsyncClustersResource: + return AsyncClustersResource(self._client) + @cached_property def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse: """ @@ -611,6 +627,10 @@ def access_keys(self) -> AccessKeysResourceWithRawResponse: def entries(self) -> EntriesResourceWithRawResponse: return EntriesResourceWithRawResponse(self._projects.entries) + @cached_property + def clusters(self) -> ClustersResourceWithRawResponse: + return ClustersResourceWithRawResponse(self._projects.clusters) + class AsyncProjectsResourceWithRawResponse: def __init__(self, projects: AsyncProjectsResource) -> None: @@ -643,6 +663,10 @@ def access_keys(self) -> AsyncAccessKeysResourceWithRawResponse: def entries(self) -> AsyncEntriesResourceWithRawResponse: return AsyncEntriesResourceWithRawResponse(self._projects.entries) + @cached_property + def clusters(self) -> AsyncClustersResourceWithRawResponse: + return AsyncClustersResourceWithRawResponse(self._projects.clusters) + class ProjectsResourceWithStreamingResponse: def __init__(self, projects: ProjectsResource) -> None: @@ -675,6 +699,10 @@ def access_keys(self) -> AccessKeysResourceWithStreamingResponse: def entries(self) -> EntriesResourceWithStreamingResponse: return EntriesResourceWithStreamingResponse(self._projects.entries) + @cached_property + def clusters(self) -> ClustersResourceWithStreamingResponse: + return ClustersResourceWithStreamingResponse(self._projects.clusters) + class AsyncProjectsResourceWithStreamingResponse: def __init__(self, projects: AsyncProjectsResource) -> None: @@ -706,3 +734,7 @@ def access_keys(self) -> AsyncAccessKeysResourceWithStreamingResponse: @cached_property def entries(self) -> AsyncEntriesResourceWithStreamingResponse: return AsyncEntriesResourceWithStreamingResponse(self._projects.entries) + + @cached_property + def clusters(self) -> AsyncClustersResourceWithStreamingResponse: + return AsyncClustersResourceWithStreamingResponse(self._projects.clusters) diff --git a/src/codex/types/projects/__init__.py b/src/codex/types/projects/__init__.py index 44c304f5..2733406c 100644 --- a/src/codex/types/projects/__init__.py +++ b/src/codex/types/projects/__init__.py @@ -4,14 +4,16 @@ from .entry import Entry as Entry from .access_key_schema import AccessKeySchema as AccessKeySchema -from .entry_list_params import EntryListParams as EntryListParams from .entry_query_params import EntryQueryParams as EntryQueryParams +from .cluster_list_params import ClusterListParams as ClusterListParams from .entry_create_params import EntryCreateParams as EntryCreateParams from .entry_update_params import EntryUpdateParams as EntryUpdateParams +from .entry_query_response import EntryQueryResponse as EntryQueryResponse +from .cluster_list_response import ClusterListResponse as ClusterListResponse from .access_key_create_params import AccessKeyCreateParams as AccessKeyCreateParams from .access_key_list_response import AccessKeyListResponse as AccessKeyListResponse from .access_key_update_params import AccessKeyUpdateParams as AccessKeyUpdateParams -from .entry_add_question_params import EntryAddQuestionParams as EntryAddQuestionParams +from .cluster_list_variants_response import ClusterListVariantsResponse as ClusterListVariantsResponse from .access_key_retrieve_project_id_response import ( AccessKeyRetrieveProjectIDResponse as AccessKeyRetrieveProjectIDResponse, ) diff --git a/src/codex/types/projects/entry_list_params.py b/src/codex/types/projects/cluster_list_params.py similarity index 66% rename from src/codex/types/projects/entry_list_params.py rename to src/codex/types/projects/cluster_list_params.py index 605ea482..438b4812 100644 --- a/src/codex/types/projects/entry_list_params.py +++ b/src/codex/types/projects/cluster_list_params.py @@ -5,20 +5,16 @@ from typing import List from typing_extensions import Literal, TypedDict -__all__ = ["EntryListParams"] +__all__ = ["ClusterListParams"] -class EntryListParams(TypedDict, total=False): - answered_only: bool - +class ClusterListParams(TypedDict, total=False): limit: int offset: int order: Literal["asc", "desc"] - sort: Literal["created_at", "answered_at"] + sort: Literal["created_at", "answered_at", "cluster_frequency_count"] states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] - - unanswered_only: bool diff --git a/src/codex/types/projects/cluster_list_response.py b/src/codex/types/projects/cluster_list_response.py new file mode 100644 index 00000000..7b4ef3ad --- /dev/null +++ b/src/codex/types/projects/cluster_list_response.py @@ -0,0 +1,36 @@ +# 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__ = ["ClusterListResponse"] + + +class ClusterListResponse(BaseModel): + id: str + + cluster_frequency_count: int + + created_at: datetime + + project_id: str + + question: str + + state: Literal["unanswered", "draft", "published", "published_with_draft"] + + answer: Optional[str] = None + + answered_at: Optional[datetime] = None + + draft_answer: Optional[str] = None + + draft_answer_last_edited: Optional[datetime] = None + + frequency_count: Optional[int] = None + """number of times the entry matched for a /query request""" + + representative_entry_id: Optional[str] = None diff --git a/src/codex/types/projects/cluster_list_variants_response.py b/src/codex/types/projects/cluster_list_variants_response.py new file mode 100644 index 00000000..aa359058 --- /dev/null +++ b/src/codex/types/projects/cluster_list_variants_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .entry import Entry +from ..._models import BaseModel + +__all__ = ["ClusterListVariantsResponse"] + + +class ClusterListVariantsResponse(BaseModel): + entries: List[Entry] + + total_count: int diff --git a/src/codex/types/projects/entry.py b/src/codex/types/projects/entry.py index 7a2c4502..442eddd8 100644 --- a/src/codex/types/projects/entry.py +++ b/src/codex/types/projects/entry.py @@ -10,14 +10,16 @@ class Entry(BaseModel): + id: str + created_at: datetime + project_id: str + question: str state: Literal["unanswered", "draft", "published", "published_with_draft"] - id: Optional[str] = None - answer: Optional[str] = None answered_at: Optional[datetime] = None @@ -25,5 +27,3 @@ class Entry(BaseModel): draft_answer: Optional[str] = None draft_answer_last_edited: Optional[datetime] = None - - frequency_count: Optional[int] = None diff --git a/src/codex/types/projects/entry_add_question_params.py b/src/codex/types/projects/entry_add_question_params.py deleted file mode 100644 index b310f96b..00000000 --- a/src/codex/types/projects/entry_add_question_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["EntryAddQuestionParams"] - - -class EntryAddQuestionParams(TypedDict, total=False): - question: Required[str] - - x_client_library_version: Annotated[str, PropertyInfo(alias="x-client-library-version")] - - x_integration_type: Annotated[str, PropertyInfo(alias="x-integration-type")] - - x_source: Annotated[str, PropertyInfo(alias="x-source")] - - x_stainless_package_version: Annotated[str, PropertyInfo(alias="x-stainless-package-version")] diff --git a/src/codex/types/projects/entry_query_response.py b/src/codex/types/projects/entry_query_response.py new file mode 100644 index 00000000..ad106d7a --- /dev/null +++ b/src/codex/types/projects/entry_query_response.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["EntryQueryResponse", "Entry"] + + +class Entry(BaseModel): + id: str + + question: str + + answer: Optional[str] = None + + draft_answer: Optional[str] = None + + +class EntryQueryResponse(BaseModel): + entry: Entry + + answer: Optional[str] = None diff --git a/src/codex/types/projects/entry_update_params.py b/src/codex/types/projects/entry_update_params.py index 05a6332d..aac256f9 100644 --- a/src/codex/types/projects/entry_update_params.py +++ b/src/codex/types/projects/entry_update_params.py @@ -15,6 +15,4 @@ class EntryUpdateParams(TypedDict, total=False): draft_answer: Optional[str] - frequency_count: Optional[int] - question: Optional[str] diff --git a/tests/api_resources/projects/test_clusters.py b/tests/api_resources/projects/test_clusters.py new file mode 100644 index 00000000..5a464970 --- /dev/null +++ b/tests/api_resources/projects/test_clusters.py @@ -0,0 +1,241 @@ +# 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 codex import Codex, AsyncCodex +from tests.utils import assert_matches_type +from codex.pagination import SyncOffsetPageClusters, AsyncOffsetPageClusters +from codex.types.projects import ClusterListResponse, ClusterListVariantsResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestClusters: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + def test_method_list(self, client: Codex) -> None: + cluster = client.projects.clusters.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(SyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_list_with_all_params(self, client: Codex) -> None: + cluster = client.projects.clusters.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + limit=1, + offset=0, + order="asc", + sort="created_at", + states=["unanswered"], + ) + assert_matches_type(SyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list(self, client: Codex) -> None: + response = client.projects.clusters.with_raw_response.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(SyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list(self, client: Codex) -> None: + with client.projects.clusters.with_streaming_response.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(SyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_path_params_list(self, client: Codex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.clusters.with_raw_response.list( + project_id="", + ) + + @pytest.mark.skip() + @parametrize + def test_method_list_variants(self, client: Codex) -> None: + cluster = client.projects.clusters.list_variants( + representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_list_variants(self, client: Codex) -> None: + response = client.projects.clusters.with_raw_response.list_variants( + representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = response.parse() + assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_list_variants(self, client: Codex) -> None: + with client.projects.clusters.with_streaming_response.list_variants( + representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = response.parse() + assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_path_params_list_variants(self, client: Codex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.clusters.with_raw_response.list_variants( + representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="", + ) + + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `representative_entry_id` but received ''" + ): + client.projects.clusters.with_raw_response.list_variants( + representative_entry_id="", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + +class TestAsyncClusters: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list(self, async_client: AsyncCodex) -> None: + cluster = await async_client.projects.clusters.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AsyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCodex) -> None: + cluster = await async_client.projects.clusters.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + limit=1, + offset=0, + order="asc", + sort="created_at", + states=["unanswered"], + ) + assert_matches_type(AsyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list(self, async_client: AsyncCodex) -> None: + response = await async_client.projects.clusters.with_raw_response.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(AsyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCodex) -> None: + async with async_client.projects.clusters.with_streaming_response.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(AsyncOffsetPageClusters[ClusterListResponse], cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_path_params_list(self, async_client: AsyncCodex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.projects.clusters.with_raw_response.list( + project_id="", + ) + + @pytest.mark.skip() + @parametrize + async def test_method_list_variants(self, async_client: AsyncCodex) -> None: + cluster = await async_client.projects.clusters.list_variants( + representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_list_variants(self, async_client: AsyncCodex) -> None: + response = await async_client.projects.clusters.with_raw_response.list_variants( + representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + cluster = await response.parse() + assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_list_variants(self, async_client: AsyncCodex) -> None: + async with async_client.projects.clusters.with_streaming_response.list_variants( + representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + cluster = await response.parse() + assert_matches_type(ClusterListVariantsResponse, cluster, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_path_params_list_variants(self, async_client: AsyncCodex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.projects.clusters.with_raw_response.list_variants( + representative_entry_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="", + ) + + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `representative_entry_id` but received ''" + ): + await async_client.projects.clusters.with_raw_response.list_variants( + representative_entry_id="", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) diff --git a/tests/api_resources/projects/test_entries.py b/tests/api_resources/projects/test_entries.py index 8a18dc01..e8965e4a 100644 --- a/tests/api_resources/projects/test_entries.py +++ b/tests/api_resources/projects/test_entries.py @@ -3,16 +3,13 @@ from __future__ import annotations import os -from typing import Any, Optional, cast +from typing import Any, cast import pytest from codex import Codex, AsyncCodex from tests.utils import assert_matches_type -from codex.pagination import SyncOffsetPageEntries, AsyncOffsetPageEntries -from codex.types.projects import ( - Entry, -) +from codex.types.projects import Entry, EntryQueryResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -150,7 +147,6 @@ def test_method_update_with_all_params(self, client: Codex) -> None: project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", answer="answer", draft_answer="draft_answer", - frequency_count=0, question="question", ) assert_matches_type(Entry, entry, path=["response"]) @@ -198,63 +194,6 @@ def test_path_params_update(self, client: Codex) -> None: project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - @pytest.mark.skip() - @parametrize - def test_method_list(self, client: Codex) -> None: - entry = client.projects.entries.list( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) - assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_method_list_with_all_params(self, client: Codex) -> None: - entry = client.projects.entries.list( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - answered_only=True, - limit=1, - offset=0, - order="asc", - sort="created_at", - states=["unanswered"], - unanswered_only=True, - ) - assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_raw_response_list(self, client: Codex) -> None: - response = client.projects.entries.with_raw_response.list( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - entry = response.parse() - assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_streaming_response_list(self, client: Codex) -> None: - with client.projects.entries.with_streaming_response.list( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - entry = response.parse() - assert_matches_type(SyncOffsetPageEntries[Entry], entry, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip() - @parametrize - def test_path_params_list(self, client: Codex) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): - client.projects.entries.with_raw_response.list( - project_id="", - ) - @pytest.mark.skip() @parametrize def test_method_delete(self, client: Codex) -> None: @@ -307,65 +246,6 @@ def test_path_params_delete(self, client: Codex) -> None: project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - @pytest.mark.skip() - @parametrize - def test_method_add_question(self, client: Codex) -> None: - entry = client.projects.entries.add_question( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - question="question", - ) - assert_matches_type(Entry, entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_method_add_question_with_all_params(self, client: Codex) -> None: - entry = client.projects.entries.add_question( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - question="question", - x_client_library_version="x-client-library-version", - x_integration_type="x-integration-type", - x_source="x-source", - x_stainless_package_version="x-stainless-package-version", - ) - assert_matches_type(Entry, entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_raw_response_add_question(self, client: Codex) -> None: - response = client.projects.entries.with_raw_response.add_question( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - entry = response.parse() - assert_matches_type(Entry, entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_streaming_response_add_question(self, client: Codex) -> None: - with client.projects.entries.with_streaming_response.add_question( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - entry = response.parse() - assert_matches_type(Entry, entry, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip() - @parametrize - def test_path_params_add_question(self, client: Codex) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): - client.projects.entries.with_raw_response.add_question( - project_id="", - question="question", - ) - @pytest.mark.skip() @parametrize def test_method_query(self, client: Codex) -> None: @@ -373,7 +253,7 @@ def test_method_query(self, client: Codex) -> None: project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", question="question", ) - assert_matches_type(Optional[Entry], entry, path=["response"]) + assert_matches_type(EntryQueryResponse, entry, path=["response"]) @pytest.mark.skip() @parametrize @@ -386,7 +266,7 @@ def test_method_query_with_all_params(self, client: Codex) -> None: x_source="x-source", x_stainless_package_version="x-stainless-package-version", ) - assert_matches_type(Optional[Entry], entry, path=["response"]) + assert_matches_type(EntryQueryResponse, entry, path=["response"]) @pytest.mark.skip() @parametrize @@ -399,7 +279,7 @@ def test_raw_response_query(self, client: Codex) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" entry = response.parse() - assert_matches_type(Optional[Entry], entry, path=["response"]) + assert_matches_type(EntryQueryResponse, entry, path=["response"]) @pytest.mark.skip() @parametrize @@ -412,7 +292,7 @@ def test_streaming_response_query(self, client: Codex) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" entry = response.parse() - assert_matches_type(Optional[Entry], entry, path=["response"]) + assert_matches_type(EntryQueryResponse, entry, path=["response"]) assert cast(Any, response.is_closed) is True @@ -559,7 +439,6 @@ async def test_method_update_with_all_params(self, async_client: AsyncCodex) -> project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", answer="answer", draft_answer="draft_answer", - frequency_count=0, question="question", ) assert_matches_type(Entry, entry, path=["response"]) @@ -607,63 +486,6 @@ async def test_path_params_update(self, async_client: AsyncCodex) -> None: project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - @pytest.mark.skip() - @parametrize - async def test_method_list(self, async_client: AsyncCodex) -> None: - entry = await async_client.projects.entries.list( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) - assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncCodex) -> None: - entry = await async_client.projects.entries.list( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - answered_only=True, - limit=1, - offset=0, - order="asc", - sort="created_at", - states=["unanswered"], - unanswered_only=True, - ) - assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_raw_response_list(self, async_client: AsyncCodex) -> None: - response = await async_client.projects.entries.with_raw_response.list( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - entry = await response.parse() - assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_streaming_response_list(self, async_client: AsyncCodex) -> None: - async with async_client.projects.entries.with_streaming_response.list( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - entry = await response.parse() - assert_matches_type(AsyncOffsetPageEntries[Entry], entry, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip() - @parametrize - async def test_path_params_list(self, async_client: AsyncCodex) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): - await async_client.projects.entries.with_raw_response.list( - project_id="", - ) - @pytest.mark.skip() @parametrize async def test_method_delete(self, async_client: AsyncCodex) -> None: @@ -716,65 +538,6 @@ async def test_path_params_delete(self, async_client: AsyncCodex) -> None: project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - @pytest.mark.skip() - @parametrize - async def test_method_add_question(self, async_client: AsyncCodex) -> None: - entry = await async_client.projects.entries.add_question( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - question="question", - ) - assert_matches_type(Entry, entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_method_add_question_with_all_params(self, async_client: AsyncCodex) -> None: - entry = await async_client.projects.entries.add_question( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - question="question", - x_client_library_version="x-client-library-version", - x_integration_type="x-integration-type", - x_source="x-source", - x_stainless_package_version="x-stainless-package-version", - ) - assert_matches_type(Entry, entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_raw_response_add_question(self, async_client: AsyncCodex) -> None: - response = await async_client.projects.entries.with_raw_response.add_question( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - question="question", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - entry = await response.parse() - assert_matches_type(Entry, entry, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_streaming_response_add_question(self, async_client: AsyncCodex) -> None: - async with async_client.projects.entries.with_streaming_response.add_question( - project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - question="question", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - entry = await response.parse() - assert_matches_type(Entry, entry, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip() - @parametrize - async def test_path_params_add_question(self, async_client: AsyncCodex) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): - await async_client.projects.entries.with_raw_response.add_question( - project_id="", - question="question", - ) - @pytest.mark.skip() @parametrize async def test_method_query(self, async_client: AsyncCodex) -> None: @@ -782,7 +545,7 @@ async def test_method_query(self, async_client: AsyncCodex) -> None: project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", question="question", ) - assert_matches_type(Optional[Entry], entry, path=["response"]) + assert_matches_type(EntryQueryResponse, entry, path=["response"]) @pytest.mark.skip() @parametrize @@ -795,7 +558,7 @@ async def test_method_query_with_all_params(self, async_client: AsyncCodex) -> N x_source="x-source", x_stainless_package_version="x-stainless-package-version", ) - assert_matches_type(Optional[Entry], entry, path=["response"]) + assert_matches_type(EntryQueryResponse, entry, path=["response"]) @pytest.mark.skip() @parametrize @@ -808,7 +571,7 @@ async def test_raw_response_query(self, async_client: AsyncCodex) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" entry = await response.parse() - assert_matches_type(Optional[Entry], entry, path=["response"]) + assert_matches_type(EntryQueryResponse, entry, path=["response"]) @pytest.mark.skip() @parametrize @@ -821,7 +584,7 @@ async def test_streaming_response_query(self, async_client: AsyncCodex) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" entry = await response.parse() - assert_matches_type(Optional[Entry], entry, path=["response"]) + assert_matches_type(EntryQueryResponse, entry, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_health.py b/tests/api_resources/test_health.py index 09700120..ed942cd2 100644 --- a/tests/api_resources/test_health.py +++ b/tests/api_resources/test_health.py @@ -73,34 +73,6 @@ def test_streaming_response_db(self, client: Codex) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip() - @parametrize - def test_method_weaviate(self, client: Codex) -> None: - health = client.health.weaviate() - assert_matches_type(HealthCheckResponse, health, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_raw_response_weaviate(self, client: Codex) -> None: - response = client.health.with_raw_response.weaviate() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - health = response.parse() - assert_matches_type(HealthCheckResponse, health, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_streaming_response_weaviate(self, client: Codex) -> None: - with client.health.with_streaming_response.weaviate() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - health = response.parse() - assert_matches_type(HealthCheckResponse, health, path=["response"]) - - assert cast(Any, response.is_closed) is True - class TestAsyncHealth: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) @@ -160,31 +132,3 @@ async def test_streaming_response_db(self, async_client: AsyncCodex) -> None: assert_matches_type(HealthCheckResponse, health, path=["response"]) assert cast(Any, response.is_closed) is True - - @pytest.mark.skip() - @parametrize - async def test_method_weaviate(self, async_client: AsyncCodex) -> None: - health = await async_client.health.weaviate() - assert_matches_type(HealthCheckResponse, health, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_raw_response_weaviate(self, async_client: AsyncCodex) -> None: - response = await async_client.health.with_raw_response.weaviate() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - health = await response.parse() - assert_matches_type(HealthCheckResponse, health, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_streaming_response_weaviate(self, async_client: AsyncCodex) -> None: - async with async_client.health.with_streaming_response.weaviate() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - health = await response.parse() - assert_matches_type(HealthCheckResponse, health, path=["response"]) - - assert cast(Any, response.is_closed) is True From 78be44a4186727fb5053099da3075f6ce81043de Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 21:15:41 +0000 Subject: [PATCH 14/14] release: 0.1.0-alpha.13 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 26 ++++++++++++++++++++++++++ pyproject.toml | 2 +- src/codex/_version.py | 2 +- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fd0ccba9..000572ec 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.12" + ".": "0.1.0-alpha.13" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index abb16021..67d337b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## 0.1.0-alpha.13 (2025-04-02) + +Full Changelog: [v0.1.0-alpha.12...v0.1.0-alpha.13](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.12...v0.1.0-alpha.13) + +### Features + +* **api:** api update ([#83](https://github.com/cleanlab/codex-python/issues/83)) ([b41e3bf](https://github.com/cleanlab/codex-python/commit/b41e3bf21e10b11b6d64e15f320cf3d8aa66bfb8)) +* **api:** api update ([#90](https://github.com/cleanlab/codex-python/issues/90)) ([52933f2](https://github.com/cleanlab/codex-python/commit/52933f2bc708e1f2b5f2e144071a9ee41b27251c)) +* **api:** updates from question grouping ([#93](https://github.com/cleanlab/codex-python/issues/93)) ([14da023](https://github.com/cleanlab/codex-python/commit/14da02311e598a1d5f4e41a100160b81befd4f61)) + + +### Bug Fixes + +* **ci:** ensure pip is always available ([#88](https://github.com/cleanlab/codex-python/issues/88)) ([86a40cc](https://github.com/cleanlab/codex-python/commit/86a40ccd3892d23bb12f78bf5ff13eaa23d8eb2d)) +* **ci:** remove publishing patch ([#89](https://github.com/cleanlab/codex-python/issues/89)) ([674c661](https://github.com/cleanlab/codex-python/commit/674c6613c7709c93cca936f086d5348041252972)) +* **types:** handle more discriminated union shapes ([#87](https://github.com/cleanlab/codex-python/issues/87)) ([ea6a942](https://github.com/cleanlab/codex-python/commit/ea6a9422c2a1ff25f14ade1a790ffd943dadbd81)) + + +### Chores + +* fix typos ([#91](https://github.com/cleanlab/codex-python/issues/91)) ([6b97689](https://github.com/cleanlab/codex-python/commit/6b97689646d7b3611ace81c630fafa1962b5c94d)) +* **internal:** bump rye to 0.44.0 ([#86](https://github.com/cleanlab/codex-python/issues/86)) ([e026b73](https://github.com/cleanlab/codex-python/commit/e026b73fb62aa19689890f14b7dcf355910029a8)) +* **internal:** codegen related update ([#85](https://github.com/cleanlab/codex-python/issues/85)) ([7e1eaca](https://github.com/cleanlab/codex-python/commit/7e1eaca4c5f2c779b264c34883688b52e1a8602e)) +* **internal:** remove extra empty newlines ([#84](https://github.com/cleanlab/codex-python/issues/84)) ([e4b2929](https://github.com/cleanlab/codex-python/commit/e4b2929d58b466199bb02e24b8e0a7c9c63f1b3a)) +* **internal:** version bump ([#81](https://github.com/cleanlab/codex-python/issues/81)) ([7ee4e09](https://github.com/cleanlab/codex-python/commit/7ee4e09545e52eaa3d10522709e833b38221ecad)) + ## 0.1.0-alpha.12 (2025-03-11) Full Changelog: [v0.1.0-alpha.11...v0.1.0-alpha.12](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.11...v0.1.0-alpha.12) diff --git a/pyproject.toml b/pyproject.toml index 61f43447..70b5b9c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "codex-sdk" -version = "0.1.0-alpha.12" +version = "0.1.0-alpha.13" description = "Internal SDK used within cleanlab-codex package. Refer to https://pypi.org/project/cleanlab-codex/ instead." dynamic = ["readme"] license = "MIT" diff --git a/src/codex/_version.py b/src/codex/_version.py index fe7cc739..8790f4ea 100644 --- a/src/codex/_version.py +++ b/src/codex/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "codex" -__version__ = "0.1.0-alpha.12" # x-release-please-version +__version__ = "0.1.0-alpha.13" # x-release-please-version