diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 08e82c45..7e56fe29 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.15" + ".": "0.1.0-alpha.16" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index ab9fbe2f..c1c522e8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,3 +1,3 @@ configured_endpoints: 36 -openapi_spec_hash: 2e10455457751c9efb36adc4399c684d +openapi_spec_hash: 6311021a3aba7ac56cc3b474762945c0 config_hash: adbedb6317fca6f566f54564cc341846 diff --git a/CHANGELOG.md b/CHANGELOG.md index cff410b1..658e0649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 0.1.0-alpha.16 (2025-04-18) + +Full Changelog: [v0.1.0-alpha.15...v0.1.0-alpha.16](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.15...v0.1.0-alpha.16) + +### Features + +* **api:** api update ([f5c1cee](https://github.com/cleanlab/codex-python/commit/f5c1cee46c42ab67bc09befff130fe88b35f06ac)) + + +### Chores + +* **internal:** base client updates ([e7d165b](https://github.com/cleanlab/codex-python/commit/e7d165b98c7536415b74fe92c558a50ee8c5861d)) +* **internal:** bump pyright version ([5eac17b](https://github.com/cleanlab/codex-python/commit/5eac17b4e3ef210077d2bed75a7d7b4954d73086)) +* **internal:** version bump ([9326b60](https://github.com/cleanlab/codex-python/commit/9326b60bf403d4a5c981b613e715ea80ef29ad8e)) + ## 0.1.0-alpha.15 (2025-04-15) Full Changelog: [v0.1.0-alpha.14...v0.1.0-alpha.15](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.14...v0.1.0-alpha.15) diff --git a/pyproject.toml b/pyproject.toml index 686a2e13..b98b79a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "codex-sdk" -version = "0.1.0-alpha.15" +version = "0.1.0-alpha.16" description = "Internal SDK used within cleanlab-codex package. Refer to https://pypi.org/project/cleanlab-codex/ instead." dynamic = ["readme"] license = "MIT" @@ -42,7 +42,7 @@ Repository = "https://github.com/cleanlab/codex-python" managed = true # version pins are in requirements-dev.lock dev-dependencies = [ - "pyright>=1.1.359", + "pyright==1.1.399", "mypy", "respx", "pytest", diff --git a/requirements-dev.lock b/requirements-dev.lock index 5b7189d6..7fcfe657 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -69,7 +69,7 @@ pydantic-core==2.27.1 # via pydantic pygments==2.18.0 # via rich -pyright==1.1.392.post0 +pyright==1.1.399 pytest==8.3.3 # via pytest-asyncio pytest-asyncio==0.24.0 diff --git a/src/codex/_base_client.py b/src/codex/_base_client.py index 564ab8a7..69be76db 100644 --- a/src/codex/_base_client.py +++ b/src/codex/_base_client.py @@ -98,7 +98,11 @@ _AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) if TYPE_CHECKING: - from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT + from httpx._config import ( + DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] + ) + + HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG else: try: from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT @@ -115,6 +119,7 @@ class PageInfo: url: URL | NotGiven params: Query | NotGiven + json: Body | NotGiven @overload def __init__( @@ -130,19 +135,30 @@ def __init__( params: Query, ) -> None: ... + @overload + def __init__( + self, + *, + json: Body, + ) -> None: ... + def __init__( self, *, url: URL | NotGiven = NOT_GIVEN, + json: Body | NotGiven = NOT_GIVEN, params: Query | NotGiven = NOT_GIVEN, ) -> None: self.url = url + self.json = json self.params = params @override def __repr__(self) -> str: if self.url: return f"{self.__class__.__name__}(url={self.url})" + if self.json: + return f"{self.__class__.__name__}(json={self.json})" return f"{self.__class__.__name__}(params={self.params})" @@ -191,6 +207,19 @@ def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: options.url = str(url) return options + if not isinstance(info.json, NotGiven): + if not is_mapping(info.json): + raise TypeError("Pagination is only supported with mappings") + + if not options.json_data: + options.json_data = {**info.json} + else: + if not is_mapping(options.json_data): + raise TypeError("Pagination is only supported with mappings") + + options.json_data = {**options.json_data, **info.json} + return options + raise ValueError("Unexpected PageInfo state") diff --git a/src/codex/_models.py b/src/codex/_models.py index 34935716..58b9263e 100644 --- a/src/codex/_models.py +++ b/src/codex/_models.py @@ -19,7 +19,6 @@ ) import pydantic -import pydantic.generics from pydantic.fields import FieldInfo from ._types import ( diff --git a/src/codex/_utils/_typing.py b/src/codex/_utils/_typing.py index 1958820f..1bac9542 100644 --- a/src/codex/_utils/_typing.py +++ b/src/codex/_utils/_typing.py @@ -110,7 +110,7 @@ class MyResponse(Foo[_T]): ``` """ cls = cast(object, get_origin(typ) or typ) - if cls in generic_bases: + if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] # we're given the class directly return extract_type_arg(typ, index) diff --git a/src/codex/_version.py b/src/codex/_version.py index d4919cf4..b99310c3 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.15" # x-release-please-version +__version__ = "0.1.0-alpha.16" # x-release-please-version diff --git a/src/codex/resources/projects/clusters.py b/src/codex/resources/projects/clusters.py index f376c0b1..e35e8ae8 100644 --- a/src/codex/resources/projects/clusters.py +++ b/src/codex/resources/projects/clusters.py @@ -50,10 +50,11 @@ def list( self, project_id: str, *, + eval_issue_types: List[Literal["hallucination", "search_failure", "unhelpful"]] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - sort: Optional[Literal["created_at", "answered_at", "cluster_frequency_count", "custom_rank"]] + sort: Optional[Literal["created_at", "answered_at", "cluster_frequency_count", "custom_rank", "eval_score"]] | 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. @@ -87,6 +88,7 @@ def list( timeout=timeout, query=maybe_transform( { + "eval_issue_types": eval_issue_types, "limit": limit, "offset": offset, "order": order, @@ -162,10 +164,11 @@ def list( self, project_id: str, *, + eval_issue_types: List[Literal["hallucination", "search_failure", "unhelpful"]] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, order: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, - sort: Optional[Literal["created_at", "answered_at", "cluster_frequency_count", "custom_rank"]] + sort: Optional[Literal["created_at", "answered_at", "cluster_frequency_count", "custom_rank", "eval_score"]] | 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. @@ -199,6 +202,7 @@ def list( timeout=timeout, query=maybe_transform( { + "eval_issue_types": eval_issue_types, "limit": limit, "offset": offset, "order": order, diff --git a/src/codex/types/projects/cluster_list_params.py b/src/codex/types/projects/cluster_list_params.py index b272d806..d1d818e3 100644 --- a/src/codex/types/projects/cluster_list_params.py +++ b/src/codex/types/projects/cluster_list_params.py @@ -9,12 +9,14 @@ class ClusterListParams(TypedDict, total=False): + eval_issue_types: List[Literal["hallucination", "search_failure", "unhelpful"]] + limit: int offset: int order: Literal["asc", "desc"] - sort: Optional[Literal["created_at", "answered_at", "cluster_frequency_count", "custom_rank"]] + sort: Optional[Literal["created_at", "answered_at", "cluster_frequency_count", "custom_rank", "eval_score"]] states: List[Literal["unanswered", "draft", "published", "published_with_draft"]] diff --git a/src/codex/types/projects/cluster_list_response.py b/src/codex/types/projects/cluster_list_response.py index 33bc18a7..c149fbdb 100644 --- a/src/codex/types/projects/cluster_list_response.py +++ b/src/codex/types/projects/cluster_list_response.py @@ -140,6 +140,10 @@ class ClusterListResponse(BaseModel): draft_answer_last_edited: Optional[datetime] = None + eval_issue_type: Optional[str] = None + + eval_score: Optional[float] = None + frequency_count: Optional[int] = None """number of times the entry matched for a /query request""" diff --git a/src/codex/types/projects/entry.py b/src/codex/types/projects/entry.py index 24d57c89..638fe352 100644 --- a/src/codex/types/projects/entry.py +++ b/src/codex/types/projects/entry.py @@ -138,5 +138,9 @@ class Entry(BaseModel): draft_answer_last_edited: Optional[datetime] = None + eval_issue_type: Optional[str] = None + + eval_score: Optional[float] = None + frequency_count: Optional[int] = None """number of times the entry matched for a /query request""" diff --git a/tests/api_resources/projects/test_clusters.py b/tests/api_resources/projects/test_clusters.py index 5a464970..53706c6c 100644 --- a/tests/api_resources/projects/test_clusters.py +++ b/tests/api_resources/projects/test_clusters.py @@ -31,6 +31,7 @@ def test_method_list(self, client: Codex) -> None: def test_method_list_with_all_params(self, client: Codex) -> None: cluster = client.projects.clusters.list( project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + eval_issue_types=["hallucination"], limit=1, offset=0, order="asc", @@ -144,6 +145,7 @@ async def test_method_list(self, async_client: AsyncCodex) -> None: 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", + eval_issue_types=["hallucination"], limit=1, offset=0, order="asc", diff --git a/tests/conftest.py b/tests/conftest.py index 8823ef7a..c93053b1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,7 @@ from codex import Codex, AsyncCodex if TYPE_CHECKING: - from _pytest.fixtures import FixtureRequest + from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] pytest.register_assert_rewrite("tests.utils") diff --git a/tests/test_models.py b/tests/test_models.py index 73e6d67c..fb9d99b1 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -832,7 +832,7 @@ class B(BaseModel): @pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") def test_type_alias_type() -> None: - Alias = TypeAliasType("Alias", str) + Alias = TypeAliasType("Alias", str) # pyright: ignore class Model(BaseModel): alias: Alias