diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d1328ca..64f9ff4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.7.0" + ".": "2.8.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 3b484e3..74e73bc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 37 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-758c3a2fbd5b7be61c8e6e0ad2e6a5ec30695747bb675960d888c497647d13d7.yml -openapi_spec_hash: 00002d90bde02f67e174368ae470c597 -config_hash: 2bea1743c84d63bd61f8501a6ea63065 +configured_endpoints: 38 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-155e4761d62255841349c0f8a01b0a9c463ea1d1f2d6c4fd8d1a75c8bef6f226.yml +openapi_spec_hash: ab91f77e7c9d992400cbc7fc8a9e76c1 +config_hash: bff282047fafdad771fb7ec685f56944 diff --git a/CHANGELOG.md b/CHANGELOG.md index 574526f..cabb035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.8.0 (2026-08-05) + +Full Changelog: [v2.7.0...v2.8.0](https://github.com/context-dot-dev/context-python-sdk/compare/v2.7.0...v2.8.0) + +### Features + +* **api:** manual updates ([d26f4e8](https://github.com/context-dot-dev/context-python-sdk/commit/d26f4e842387b630ba30fcb291bbcdbad610d28c)) + ## 2.7.0 (2026-08-01) Full Changelog: [v2.6.0...v2.7.0](https://github.com/context-dot-dev/context-python-sdk/compare/v2.6.0...v2.7.0) diff --git a/api.md b/api.md index 7040315..61a5c97 100644 --- a/api.md +++ b/api.md @@ -62,13 +62,18 @@ Methods: Types: ```python -from context.dev.types import BrandRetrieveResponse, BrandRetrieveSimplifiedResponse +from context.dev.types import ( + BrandRetrieveResponse, + BrandRetrieveSimplifiedResponse, + BrandSearchResponse, +) ``` Methods: - client.brand.retrieve(\*\*params) -> BrandRetrieveResponse - client.brand.retrieve_simplified(\*\*params) -> BrandRetrieveSimplifiedResponse +- client.brand.search(\*\*params) -> BrandSearchResponse # Industry diff --git a/pyproject.toml b/pyproject.toml index fb0dfb2..ece6698 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "context.dev" -version = "2.7.0" +version = "2.8.0" description = "The official Python library for the context.dev API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/context/dev/_version.py b/src/context/dev/_version.py index 31f9889..c08edfc 100644 --- a/src/context/dev/_version.py +++ b/src/context/dev/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "context.dev" -__version__ = "2.7.0" # x-release-please-version +__version__ = "2.8.0" # x-release-please-version diff --git a/src/context/dev/resources/brand.py b/src/context/dev/resources/brand.py index 65cf230..cf8f895 100644 --- a/src/context/dev/resources/brand.py +++ b/src/context/dev/resources/brand.py @@ -7,7 +7,7 @@ import httpx -from ..types import brand_retrieve_params, brand_retrieve_simplified_params +from ..types import brand_search_params, brand_retrieve_params, brand_retrieve_simplified_params from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from .._utils import required_args, maybe_transform, async_maybe_transform from .._compat import cached_property @@ -19,6 +19,7 @@ async_to_streamed_response_wrapper, ) from .._base_client import make_request_options +from ..types.brand_search_response import BrandSearchResponse from ..types.brand_retrieve_response import BrandRetrieveResponse from ..types.brand_retrieve_simplified_response import BrandRetrieveSimplifiedResponse @@ -1273,6 +1274,61 @@ def retrieve_simplified( cast_to=BrandRetrieveSimplifiedResponse, ) + def search( + self, + *, + query: str, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandSearchResponse: + """ + Search brands by name or domain and get back up to 10 lightweight matches + (domain, name, logo), most popular first: by Tranco rank, then market cap for + brands outside the Tranco list, with text relevance breaking ties. Matching is + prefix-based with no typo tolerance, so it is suited to autocomplete. Only + brands already in the Context.dev index are returned — use /brand/retrieve to + fetch (and index) a specific domain. Free on Pro and Scale plans; costs 1 credit + per request on the Free and Starter plans. + + Args: + query: Search term, matched against brand names and domains by prefix (e.g. 'nike', + 'nike.com', 'nik'). + + tags: Optional comma-separated caller-defined tags for tracking this request. Tags are + recorded on the request's usage log and can be used to filter usage on the + dashboard usage page. Up to 20 tags, each 1-50 characters. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/brand/search", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "query": query, + "tags": tags, + }, + brand_search_params.BrandSearchParams, + ), + ), + cast_to=BrandSearchResponse, + ) + class AsyncBrandResource(AsyncAPIResource): @cached_property @@ -2522,6 +2578,61 @@ async def retrieve_simplified( cast_to=BrandRetrieveSimplifiedResponse, ) + async def search( + self, + *, + query: str, + tags: SequenceNotStr[str] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandSearchResponse: + """ + Search brands by name or domain and get back up to 10 lightweight matches + (domain, name, logo), most popular first: by Tranco rank, then market cap for + brands outside the Tranco list, with text relevance breaking ties. Matching is + prefix-based with no typo tolerance, so it is suited to autocomplete. Only + brands already in the Context.dev index are returned — use /brand/retrieve to + fetch (and index) a specific domain. Free on Pro and Scale plans; costs 1 credit + per request on the Free and Starter plans. + + Args: + query: Search term, matched against brand names and domains by prefix (e.g. 'nike', + 'nike.com', 'nik'). + + tags: Optional comma-separated caller-defined tags for tracking this request. Tags are + recorded on the request's usage log and can be used to filter usage on the + dashboard usage page. Up to 20 tags, each 1-50 characters. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/brand/search", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "query": query, + "tags": tags, + }, + brand_search_params.BrandSearchParams, + ), + ), + cast_to=BrandSearchResponse, + ) + class BrandResourceWithRawResponse: def __init__(self, brand: BrandResource) -> None: @@ -2533,6 +2644,9 @@ def __init__(self, brand: BrandResource) -> None: self.retrieve_simplified = to_raw_response_wrapper( brand.retrieve_simplified, ) + self.search = to_raw_response_wrapper( + brand.search, + ) class AsyncBrandResourceWithRawResponse: @@ -2545,6 +2659,9 @@ def __init__(self, brand: AsyncBrandResource) -> None: self.retrieve_simplified = async_to_raw_response_wrapper( brand.retrieve_simplified, ) + self.search = async_to_raw_response_wrapper( + brand.search, + ) class BrandResourceWithStreamingResponse: @@ -2557,6 +2674,9 @@ def __init__(self, brand: BrandResource) -> None: self.retrieve_simplified = to_streamed_response_wrapper( brand.retrieve_simplified, ) + self.search = to_streamed_response_wrapper( + brand.search, + ) class AsyncBrandResourceWithStreamingResponse: @@ -2569,3 +2689,6 @@ def __init__(self, brand: AsyncBrandResource) -> None: self.retrieve_simplified = async_to_streamed_response_wrapper( brand.retrieve_simplified, ) + self.search = async_to_streamed_response_wrapper( + brand.search, + ) diff --git a/src/context/dev/types/__init__.py b/src/context/dev/types/__init__.py index efea4d2..11b8a4a 100644 --- a/src/context/dev/types/__init__.py +++ b/src/context/dev/types/__init__.py @@ -12,6 +12,7 @@ from .web_extract_params import WebExtractParams as WebExtractParams from .batch_list_response import BatchListResponse as BatchListResponse from .batch_submit_params import BatchSubmitParams as BatchSubmitParams +from .brand_search_params import BrandSearchParams as BrandSearchParams from .monitor_list_params import MonitorListParams as MonitorListParams from .parse_handle_params import ParseHandleParams as ParseHandleParams from .web_search_response import WebSearchResponse as WebSearchResponse @@ -20,6 +21,7 @@ from .batch_cancel_response import BatchCancelResponse as BatchCancelResponse from .batch_submit_response import BatchSubmitResponse as BatchSubmitResponse from .brand_retrieve_params import BrandRetrieveParams as BrandRetrieveParams +from .brand_search_response import BrandSearchResponse as BrandSearchResponse from .monitor_create_params import MonitorCreateParams as MonitorCreateParams from .monitor_list_response import MonitorListResponse as MonitorListResponse from .monitor_update_params import MonitorUpdateParams as MonitorUpdateParams diff --git a/src/context/dev/types/brand_search_params.py b/src/context/dev/types/brand_search_params.py new file mode 100644 index 0000000..911d0c5 --- /dev/null +++ b/src/context/dev/types/brand_search_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .._types import SequenceNotStr + +__all__ = ["BrandSearchParams"] + + +class BrandSearchParams(TypedDict, total=False): + query: Required[str] + """Search term, matched against brand names and domains by prefix (e.g. + + 'nike', 'nike.com', 'nik'). + """ + + tags: SequenceNotStr[str] + """Optional comma-separated caller-defined tags for tracking this request. + + Tags are recorded on the request's usage log and can be used to filter usage on + the dashboard usage page. Up to 20 tags, each 1-50 characters. + """ diff --git a/src/context/dev/types/brand_search_response.py b/src/context/dev/types/brand_search_response.py new file mode 100644 index 0000000..f2b46ed --- /dev/null +++ b/src/context/dev/types/brand_search_response.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["BrandSearchResponse", "Result", "KeyMetadata"] + + +class Result(BaseModel): + domain: str + """The brand's domain.""" + + logo: str + """ + Logo link URL that serves the brand's logo, generated per request for the + calling organization. + """ + + name: str + """The brand's name. Empty string when unknown.""" + + +class KeyMetadata(BaseModel): + """Metadata about the API key used for the request. + + Included in every response whenever a valid API key is provided, even when the response status is not 200. + """ + + credits_consumed: int + """The number of credits consumed by this request.""" + + credits_remaining: int + """The number of credits remaining for your organization after this request.""" + + +class BrandSearchResponse(BaseModel): + results: List[Result] + """Up to 10 matching brands, most popular first. Empty when nothing matches.""" + + key_metadata: Optional[KeyMetadata] = None + """Metadata about the API key used for the request. + + Included in every response whenever a valid API key is provided, even when the + response status is not 200. + """ diff --git a/tests/api_resources/test_brand.py b/tests/api_resources/test_brand.py index 9e921a6..d0912d0 100644 --- a/tests/api_resources/test_brand.py +++ b/tests/api_resources/test_brand.py @@ -10,6 +10,7 @@ from context.dev import ContextDev, AsyncContextDev from tests.utils import assert_matches_type from context.dev.types import ( + BrandSearchResponse, BrandRetrieveResponse, BrandRetrieveSimplifiedResponse, ) @@ -375,6 +376,49 @@ def test_streaming_response_retrieve_simplified(self, client: ContextDev) -> Non assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_search(self, client: ContextDev) -> None: + brand = client.brand.search( + query="x", + ) + assert_matches_type(BrandSearchResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_search_with_all_params(self, client: ContextDev) -> None: + brand = client.brand.search( + query="x", + tags=["production", "team-alpha"], + ) + assert_matches_type(BrandSearchResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_search(self, client: ContextDev) -> None: + response = client.brand.with_raw_response.search( + query="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = response.parse() + assert_matches_type(BrandSearchResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_search(self, client: ContextDev) -> None: + with client.brand.with_streaming_response.search( + query="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = response.parse() + assert_matches_type(BrandSearchResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncBrand: parametrize = pytest.mark.parametrize( @@ -735,3 +779,46 @@ async def test_streaming_response_retrieve_simplified(self, async_client: AsyncC assert_matches_type(BrandRetrieveSimplifiedResponse, brand, path=["response"]) assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_search(self, async_client: AsyncContextDev) -> None: + brand = await async_client.brand.search( + query="x", + ) + assert_matches_type(BrandSearchResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_search_with_all_params(self, async_client: AsyncContextDev) -> None: + brand = await async_client.brand.search( + query="x", + tags=["production", "team-alpha"], + ) + assert_matches_type(BrandSearchResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_search(self, async_client: AsyncContextDev) -> None: + response = await async_client.brand.with_raw_response.search( + query="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = await response.parse() + assert_matches_type(BrandSearchResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_search(self, async_client: AsyncContextDev) -> None: + async with async_client.brand.with_streaming_response.search( + query="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = await response.parse() + assert_matches_type(BrandSearchResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True