From f2d6a4c509ae5ce57fc64c592b3e5039cf40a9ba Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 24 Jan 2026 06:43:20 +0000 Subject: [PATCH 01/11] chore(ci): upgrade `actions/github-script` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 495c681..60b11b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,7 @@ jobs: - name: Get GitHub OIDC Token if: github.repository == 'stainless-sdks/zeroentropy-python' id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); From 16fc2820ec1e883128e16be9f296b1070666f199 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 06:25:15 +0000 Subject: [PATCH 02/11] feat(client): add custom JSON encoder for extended type support --- src/zeroentropy/_base_client.py | 7 +- src/zeroentropy/_compat.py | 6 +- src/zeroentropy/_utils/_json.py | 35 +++++++++ tests/test_utils/test_json.py | 126 ++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 src/zeroentropy/_utils/_json.py create mode 100644 tests/test_utils/test_json.py diff --git a/src/zeroentropy/_base_client.py b/src/zeroentropy/_base_client.py index ea48701..ddeaa86 100644 --- a/src/zeroentropy/_base_client.py +++ b/src/zeroentropy/_base_client.py @@ -86,6 +86,7 @@ APIConnectionError, APIResponseValidationError, ) +from ._utils._json import openapi_dumps log: logging.Logger = logging.getLogger(__name__) @@ -554,8 +555,10 @@ def _build_request( kwargs["content"] = options.content elif isinstance(json_data, bytes): kwargs["content"] = json_data - else: - kwargs["json"] = json_data if is_given(json_data) else None + elif not files: + # Don't set content when JSON is sent as multipart/form-data, + # since httpx's content param overrides other body arguments + kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None kwargs["files"] = files else: headers.pop("Content-Type", None) diff --git a/src/zeroentropy/_compat.py b/src/zeroentropy/_compat.py index bdef67f..786ff42 100644 --- a/src/zeroentropy/_compat.py +++ b/src/zeroentropy/_compat.py @@ -139,6 +139,7 @@ def model_dump( exclude_defaults: bool = False, warnings: bool = True, mode: Literal["json", "python"] = "python", + by_alias: bool | None = None, ) -> dict[str, Any]: if (not PYDANTIC_V1) or hasattr(model, "model_dump"): return model.model_dump( @@ -148,13 +149,12 @@ def model_dump( exclude_defaults=exclude_defaults, # warnings are not supported in Pydantic v1 warnings=True if PYDANTIC_V1 else warnings, + by_alias=by_alias, ) return cast( "dict[str, Any]", model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - exclude=exclude, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, + exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) ), ) diff --git a/src/zeroentropy/_utils/_json.py b/src/zeroentropy/_utils/_json.py new file mode 100644 index 0000000..6058421 --- /dev/null +++ b/src/zeroentropy/_utils/_json.py @@ -0,0 +1,35 @@ +import json +from typing import Any +from datetime import datetime +from typing_extensions import override + +import pydantic + +from .._compat import model_dump + + +def openapi_dumps(obj: Any) -> bytes: + """ + Serialize an object to UTF-8 encoded JSON bytes. + + Extends the standard json.dumps with support for additional types + commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc. + """ + return json.dumps( + obj, + cls=_CustomEncoder, + # Uses the same defaults as httpx's JSON serialization + ensure_ascii=False, + separators=(",", ":"), + allow_nan=False, + ).encode() + + +class _CustomEncoder(json.JSONEncoder): + @override + def default(self, o: Any) -> Any: + if isinstance(o, datetime): + return o.isoformat() + if isinstance(o, pydantic.BaseModel): + return model_dump(o, exclude_unset=True, mode="json", by_alias=True) + return super().default(o) diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py new file mode 100644 index 0000000..f6fc961 --- /dev/null +++ b/tests/test_utils/test_json.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +import datetime +from typing import Union + +import pydantic + +from zeroentropy import _compat +from zeroentropy._utils._json import openapi_dumps + + +class TestOpenapiDumps: + def test_basic(self) -> None: + data = {"key": "value", "number": 42} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"key":"value","number":42}' + + def test_datetime_serialization(self) -> None: + dt = datetime.datetime(2023, 1, 1, 12, 0, 0) + data = {"datetime": dt} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"datetime":"2023-01-01T12:00:00"}' + + def test_pydantic_model_serialization(self) -> None: + class User(pydantic.BaseModel): + first_name: str + last_name: str + age: int + + model_instance = User(first_name="John", last_name="Kramer", age=83) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"first_name":"John","last_name":"Kramer","age":83}}' + + def test_pydantic_model_with_default_values(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + score: int = 0 + + model_instance = User(name="Alice") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Alice"}}' + + def test_pydantic_model_with_default_values_overridden(self) -> None: + class User(pydantic.BaseModel): + name: str + role: str = "user" + active: bool = True + + model_instance = User(name="Bob", role="admin", active=False) + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Bob","role":"admin","active":false}}' + + def test_pydantic_model_with_alias(self) -> None: + class User(pydantic.BaseModel): + first_name: str = pydantic.Field(alias="firstName") + last_name: str = pydantic.Field(alias="lastName") + + model_instance = User(firstName="John", lastName="Doe") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"firstName":"John","lastName":"Doe"}}' + + def test_pydantic_model_with_alias_and_default(self) -> None: + class User(pydantic.BaseModel): + user_name: str = pydantic.Field(alias="userName") + user_role: str = pydantic.Field(default="member", alias="userRole") + is_active: bool = pydantic.Field(default=True, alias="isActive") + + model_instance = User(userName="charlie") + data = {"model": model_instance} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"charlie"}}' + + model_with_overrides = User(userName="diana", userRole="admin", isActive=False) + data = {"model": model_with_overrides} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"userName":"diana","userRole":"admin","isActive":false}}' + + def test_pydantic_model_with_nested_models_and_defaults(self) -> None: + class Address(pydantic.BaseModel): + street: str + city: str = "Unknown" + + class User(pydantic.BaseModel): + name: str + address: Address + verified: bool = False + + if _compat.PYDANTIC_V1: + # to handle forward references in Pydantic v1 + User.update_forward_refs(**locals()) # type: ignore[reportDeprecated] + + address = Address(street="123 Main St") + user = User(name="Diana", address=address) + data = {"user": user} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"user":{"name":"Diana","address":{"street":"123 Main St"}}}' + + address_with_city = Address(street="456 Oak Ave", city="Boston") + user_verified = User(name="Eve", address=address_with_city, verified=True) + data = {"user": user_verified} + json_bytes = openapi_dumps(data) + assert ( + json_bytes == b'{"user":{"name":"Eve","address":{"street":"456 Oak Ave","city":"Boston"},"verified":true}}' + ) + + def test_pydantic_model_with_optional_fields(self) -> None: + class User(pydantic.BaseModel): + name: str + email: Union[str, None] + phone: Union[str, None] + + model_with_none = User(name="Eve", email=None, phone=None) + data = {"model": model_with_none} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Eve","email":null,"phone":null}}' + + model_with_values = User(name="Frank", email="frank@example.com", phone=None) + data = {"model": model_with_values} + json_bytes = openapi_dumps(data) + assert json_bytes == b'{"model":{"name":"Frank","email":"frank@example.com","phone":null}}' From 1fd1cce350f354877437976a2f795cf810c6e039 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 06:42:45 +0000 Subject: [PATCH 03/11] chore(internal): bump dependencies --- requirements-dev.lock | 20 ++++++++++---------- requirements.lock | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 9904783..eb2e668 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -12,14 +12,14 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.13.2 +aiohttp==3.13.3 # via httpx-aiohttp # via zeroentropy aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 # via pydantic -anyio==4.12.0 +anyio==4.12.1 # via httpx # via zeroentropy argcomplete==3.6.3 @@ -31,7 +31,7 @@ attrs==25.4.0 # via nox backports-asyncio-runner==1.2.0 # via pytest-asyncio -certifi==2025.11.12 +certifi==2026.1.4 # via httpcore # via httpx colorlog==6.10.1 @@ -61,7 +61,7 @@ httpx==0.28.1 # via httpx-aiohttp # via respx # via zeroentropy -httpx-aiohttp==0.1.9 +httpx-aiohttp==0.1.12 # via zeroentropy humanize==4.13.0 # via nox @@ -69,7 +69,7 @@ idna==3.11 # via anyio # via httpx # via yarl -importlib-metadata==8.7.0 +importlib-metadata==8.7.1 iniconfig==2.1.0 # via pytest markdown-it-py==3.0.0 @@ -82,14 +82,14 @@ multidict==6.7.0 mypy==1.17.0 mypy-extensions==1.1.0 # via mypy -nodeenv==1.9.1 +nodeenv==1.10.0 # via pyright nox==2025.11.12 packaging==25.0 # via dependency-groups # via nox # via pytest -pathspec==0.12.1 +pathspec==1.0.3 # via mypy platformdirs==4.4.0 # via virtualenv @@ -115,13 +115,13 @@ python-dateutil==2.9.0.post0 # via time-machine respx==0.22.0 rich==14.2.0 -ruff==0.14.7 +ruff==0.14.13 six==1.17.0 # via python-dateutil sniffio==1.3.1 # via zeroentropy time-machine==2.19.0 -tomli==2.3.0 +tomli==2.4.0 # via dependency-groups # via mypy # via nox @@ -141,7 +141,7 @@ typing-extensions==4.15.0 # via zeroentropy typing-inspection==0.4.2 # via pydantic -virtualenv==20.35.4 +virtualenv==20.36.1 # via nox yarl==1.22.0 # via aiohttp diff --git a/requirements.lock b/requirements.lock index 4f59ec7..b609058 100644 --- a/requirements.lock +++ b/requirements.lock @@ -12,21 +12,21 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.13.2 +aiohttp==3.13.3 # via httpx-aiohttp # via zeroentropy aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 # via pydantic -anyio==4.12.0 +anyio==4.12.1 # via httpx # via zeroentropy async-timeout==5.0.1 # via aiohttp attrs==25.4.0 # via aiohttp -certifi==2025.11.12 +certifi==2026.1.4 # via httpcore # via httpx distro==1.9.0 @@ -43,7 +43,7 @@ httpcore==1.0.9 httpx==0.28.1 # via httpx-aiohttp # via zeroentropy -httpx-aiohttp==0.1.9 +httpx-aiohttp==0.1.12 # via zeroentropy idna==3.11 # via anyio From 31de67c7c1b148810644411e0d62a9ef1eb6fa7e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 08:44:58 +0000 Subject: [PATCH 04/11] chore(internal): fix lint error on Python 3.14 --- src/zeroentropy/_utils/_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zeroentropy/_utils/_compat.py b/src/zeroentropy/_utils/_compat.py index dd70323..2c70b29 100644 --- a/src/zeroentropy/_utils/_compat.py +++ b/src/zeroentropy/_utils/_compat.py @@ -26,7 +26,7 @@ def is_union(tp: Optional[Type[Any]]) -> bool: else: import types - return tp is Union or tp is types.UnionType + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] def is_typeddict(tp: Type[Any]) -> bool: From fbc0e7e1d385c141f59a3b3c674fd78bdeea879a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 05:36:04 +0000 Subject: [PATCH 05/11] chore: format all `api.md` files --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2512f10..957bc7a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,7 @@ format = { chain = [ # run formatting again to fix any inconsistencies when imports are stripped "format:ruff", ]} -"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" +"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" "format:ruff" = "ruff format" "lint" = { chain = [ From 78e43f9c7dc3216aaba24fdf9893103279b91fff Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 08:13:21 +0000 Subject: [PATCH 06/11] chore: update mock server docs --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e66002e..7918a64 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,8 +88,7 @@ $ pip install ./path-to-wheel-file.whl Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. ```sh -# you will need npm installed -$ npx prism mock path/to/your/openapi.yml +$ ./scripts/mock ``` ```sh From 1c67b643e2c6d48d53123e404f0b89f8a9178713 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 08:28:20 +0000 Subject: [PATCH 07/11] chore(internal): add request options to SSE classes --- src/zeroentropy/_response.py | 3 +++ src/zeroentropy/_streaming.py | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/zeroentropy/_response.py b/src/zeroentropy/_response.py index f63ea68..53510bc 100644 --- a/src/zeroentropy/_response.py +++ b/src/zeroentropy/_response.py @@ -152,6 +152,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: ), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -162,6 +163,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -175,6 +177,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) diff --git a/src/zeroentropy/_streaming.py b/src/zeroentropy/_streaming.py index 838d5cd..efde25b 100644 --- a/src/zeroentropy/_streaming.py +++ b/src/zeroentropy/_streaming.py @@ -4,7 +4,7 @@ import json import inspect from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast +from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable import httpx @@ -13,6 +13,7 @@ if TYPE_CHECKING: from ._client import ZeroEntropy, AsyncZeroEntropy + from ._models import FinalRequestOptions _T = TypeVar("_T") @@ -22,7 +23,7 @@ class Stream(Generic[_T]): """Provides the core interface to iterate over a synchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEBytesDecoder def __init__( @@ -31,10 +32,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: ZeroEntropy, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() @@ -85,7 +88,7 @@ class AsyncStream(Generic[_T]): """Provides the core interface to iterate over an asynchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEDecoder | SSEBytesDecoder def __init__( @@ -94,10 +97,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: AsyncZeroEntropy, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() From ed5da0254ec6327ac53a498380975e0d0f985681 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 08:40:16 +0000 Subject: [PATCH 08/11] chore(internal): make `test_proxy_environment_variables` more resilient --- tests/test_client.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 68c5407..2957217 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -957,6 +957,8 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has this set + monkeypatch.delenv("HTTP_PROXY", raising=False) client = DefaultHttpxClient() @@ -1865,6 +1867,8 @@ async def test_get_platform(self) -> None: async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has this set + monkeypatch.delenv("HTTP_PROXY", raising=False) client = DefaultAsyncHttpxClient() From 1f31fae37fe8f8b789e7d1303311d2a657a932a2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:21:11 +0000 Subject: [PATCH 09/11] chore(internal): make `test_proxy_environment_variables` more resilient to env --- tests/test_client.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 2957217..6582560 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -957,8 +957,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") - # Delete in case our environment has this set + # Delete in case our environment has any proxy env vars set monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultHttpxClient() @@ -1867,8 +1873,14 @@ async def test_get_platform(self) -> None: async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") - # Delete in case our environment has this set + # Delete in case our environment has any proxy env vars set monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultAsyncHttpxClient() From d172a59fa7fe5e224aee24fd345c8ba1e69a1233 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 06:36:04 +0000 Subject: [PATCH 10/11] feat(api): manual updates --- .stats.yml | 4 +-- src/zeroentropy/resources/queries.py | 10 ++++++ .../types/query_top_pages_params.py | 6 ++++ .../types/query_top_pages_response.py | 35 +++++++++++++++++-- tests/api_resources/test_queries.py | 2 ++ 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9da5d63..1d67610 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/zeroentropy%2Fzeroentropy-b5badb1383675a2606a4e65b515426cf70010d0e834372de7bcf39fda4939692.yml -openapi_spec_hash: b3b0c03c89fe5ea66cc91fea2fa9726b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/zeroentropy%2Fzeroentropy-cd86445a8ef095a12e7bf74baddc7d5a8225531f8edb88ba613e12a52e219a42.yml +openapi_spec_hash: 6da635b19c554a476ea9c967b619ae5b config_hash: f5fb1effd4b0e263e1e93de3f573f46f diff --git a/src/zeroentropy/resources/queries.py b/src/zeroentropy/resources/queries.py index 6e89238..fb8eb79 100644 --- a/src/zeroentropy/resources/queries.py +++ b/src/zeroentropy/resources/queries.py @@ -130,6 +130,7 @@ def top_pages( query: str, filter: Optional[Dict[str, object]] | Omit = omit, include_content: bool | Omit = omit, + include_metadata: bool | Omit = omit, latency_mode: Literal["low", "high"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -155,6 +156,9 @@ def top_pages( include_content: If set to true, then the content of all pages will be returned. + include_metadata: Whether or not to include the document metadata in the response. If not + provided, then the default will be `False`. + latency_mode: This option selects between our two latency modes. The higher latency mode takes longer, but can allow for more accurate responses. If desired, test both to customize your search experience for your particular use-case, or use the @@ -178,6 +182,7 @@ def top_pages( "query": query, "filter": filter, "include_content": include_content, + "include_metadata": include_metadata, "latency_mode": latency_mode, }, query_top_pages_params.QueryTopPagesParams, @@ -371,6 +376,7 @@ async def top_pages( query: str, filter: Optional[Dict[str, object]] | Omit = omit, include_content: bool | Omit = omit, + include_metadata: bool | Omit = omit, latency_mode: Literal["low", "high"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -396,6 +402,9 @@ async def top_pages( include_content: If set to true, then the content of all pages will be returned. + include_metadata: Whether or not to include the document metadata in the response. If not + provided, then the default will be `False`. + latency_mode: This option selects between our two latency modes. The higher latency mode takes longer, but can allow for more accurate responses. If desired, test both to customize your search experience for your particular use-case, or use the @@ -419,6 +428,7 @@ async def top_pages( "query": query, "filter": filter, "include_content": include_content, + "include_metadata": include_metadata, "latency_mode": latency_mode, }, query_top_pages_params.QueryTopPagesParams, diff --git a/src/zeroentropy/types/query_top_pages_params.py b/src/zeroentropy/types/query_top_pages_params.py index 8a97698..370e4e9 100644 --- a/src/zeroentropy/types/query_top_pages_params.py +++ b/src/zeroentropy/types/query_top_pages_params.py @@ -32,6 +32,12 @@ class QueryTopPagesParams(TypedDict, total=False): include_content: bool """If set to true, then the content of all pages will be returned.""" + include_metadata: bool + """Whether or not to include the document metadata in the response. + + If not provided, then the default will be `False`. + """ + latency_mode: Literal["low", "high"] """This option selects between our two latency modes. diff --git a/src/zeroentropy/types/query_top_pages_response.py b/src/zeroentropy/types/query_top_pages_response.py index ca243f1..2990cae 100644 --- a/src/zeroentropy/types/query_top_pages_response.py +++ b/src/zeroentropy/types/query_top_pages_response.py @@ -1,10 +1,33 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import Dict, List, Union, Optional from .._models import BaseModel -__all__ = ["QueryTopPagesResponse", "Result"] +__all__ = ["QueryTopPagesResponse", "DocumentResult", "Result"] + + +class DocumentResult(BaseModel): + file_url: str + """ + A URL to the document data, which can be used to download the raw document + content or to display the document in frontend applications. + + NOTE: If a `/documents/update-document` call returned a new document id, then + this url will be invalidated and must be retrieved again. + """ + + metadata: Optional[Dict[str, Union[str, List[str]]]] = None + """The metadata for that document. + + Will be `None` if `include_metadata` is `False`. + """ + + path: str + """The path of the document.""" + + score: float + """The relevancy score assigned to this document.""" class Result(BaseModel): @@ -43,4 +66,12 @@ class Result(BaseModel): class QueryTopPagesResponse(BaseModel): + document_results: List[DocumentResult] + """The array of associated document information. + + Note how each result page has an associated document path. After deduplicating + the document paths, this array will contain document info for each document path + that is referenced by at least one page result. + """ + results: List[Result] diff --git a/tests/api_resources/test_queries.py b/tests/api_resources/test_queries.py index 80e938c..51091c0 100644 --- a/tests/api_resources/test_queries.py +++ b/tests/api_resources/test_queries.py @@ -88,6 +88,7 @@ def test_method_top_pages_with_all_params(self, client: ZeroEntropy) -> None: query="query", filter={"foo": "bar"}, include_content=True, + include_metadata=True, latency_mode="low", ) assert_matches_type(QueryTopPagesResponse, query, path=["response"]) @@ -243,6 +244,7 @@ async def test_method_top_pages_with_all_params(self, async_client: AsyncZeroEnt query="query", filter={"foo": "bar"}, include_content=True, + include_metadata=True, latency_mode="low", ) assert_matches_type(QueryTopPagesResponse, query, path=["response"]) From 725135ab8916951bfb6580c3eb10e64723251df3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 06:36:22 +0000 Subject: [PATCH 11/11] release: 0.1.0-alpha.9 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 21 +++++++++++++++++++++ pyproject.toml | 2 +- src/zeroentropy/_version.py | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c373724..46b9b6b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.8" + ".": "0.1.0-alpha.9" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8034868..a024c59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 0.1.0-alpha.9 (2026-03-03) + +Full Changelog: [v0.1.0-alpha.8...v0.1.0-alpha.9](https://github.com/zeroentropy-ai/zeroentropy-python/compare/v0.1.0-alpha.8...v0.1.0-alpha.9) + +### Features + +* **api:** manual updates ([d172a59](https://github.com/zeroentropy-ai/zeroentropy-python/commit/d172a59fa7fe5e224aee24fd345c8ba1e69a1233)) +* **client:** add custom JSON encoder for extended type support ([16fc282](https://github.com/zeroentropy-ai/zeroentropy-python/commit/16fc2820ec1e883128e16be9f296b1070666f199)) + + +### Chores + +* **ci:** upgrade `actions/github-script` ([f2d6a4c](https://github.com/zeroentropy-ai/zeroentropy-python/commit/f2d6a4c509ae5ce57fc64c592b3e5039cf40a9ba)) +* format all `api.md` files ([fbc0e7e](https://github.com/zeroentropy-ai/zeroentropy-python/commit/fbc0e7e1d385c141f59a3b3c674fd78bdeea879a)) +* **internal:** add request options to SSE classes ([1c67b64](https://github.com/zeroentropy-ai/zeroentropy-python/commit/1c67b643e2c6d48d53123e404f0b89f8a9178713)) +* **internal:** bump dependencies ([1fd1cce](https://github.com/zeroentropy-ai/zeroentropy-python/commit/1fd1cce350f354877437976a2f795cf810c6e039)) +* **internal:** fix lint error on Python 3.14 ([31de67c](https://github.com/zeroentropy-ai/zeroentropy-python/commit/31de67c7c1b148810644411e0d62a9ef1eb6fa7e)) +* **internal:** make `test_proxy_environment_variables` more resilient ([ed5da02](https://github.com/zeroentropy-ai/zeroentropy-python/commit/ed5da0254ec6327ac53a498380975e0d0f985681)) +* **internal:** make `test_proxy_environment_variables` more resilient to env ([1f31fae](https://github.com/zeroentropy-ai/zeroentropy-python/commit/1f31fae37fe8f8b789e7d1303311d2a657a932a2)) +* update mock server docs ([78e43f9](https://github.com/zeroentropy-ai/zeroentropy-python/commit/78e43f9c7dc3216aaba24fdf9893103279b91fff)) + ## 0.1.0-alpha.8 (2026-01-21) Full Changelog: [v0.1.0-alpha.7...v0.1.0-alpha.8](https://github.com/zeroentropy-ai/zeroentropy-python/compare/v0.1.0-alpha.7...v0.1.0-alpha.8) diff --git a/pyproject.toml b/pyproject.toml index 957bc7a..4fe374f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "zeroentropy" -version = "0.1.0-alpha.8" +version = "0.1.0-alpha.9" description = "The official Python library for the ZeroEntropy API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/zeroentropy/_version.py b/src/zeroentropy/_version.py index 69be61f..61ae32c 100644 --- a/src/zeroentropy/_version.py +++ b/src/zeroentropy/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "zeroentropy" -__version__ = "0.1.0-alpha.8" # x-release-please-version +__version__ = "0.1.0-alpha.9" # x-release-please-version