From ad26494daca49a55899f9e769e9b38e20f51857a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 02:21:26 +0000 Subject: [PATCH 01/12] fix(ci): correct conditional --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e60c76..38fa79b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,14 +36,13 @@ jobs: run: ./scripts/lint upload: - if: github.repository == 'stainless-sdks/brand.dev-python' + if: github.repository == 'stainless-sdks/brand.dev-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 name: upload permissions: contents: read id-token: write runs-on: depot-ubuntu-24.04 - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 From 9f67ed039e0b905f81d8c1e1a1bd79e9c997d483 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 04:57:11 +0000 Subject: [PATCH 02/12] chore(ci): change upload type --- .github/workflows/ci.yml | 18 ++++++++++++++++-- scripts/utils/upload-artifact.sh | 12 +++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38fa79b..bd39ae7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,10 +35,10 @@ jobs: - name: Run lints run: ./scripts/lint - upload: + build: if: github.repository == 'stainless-sdks/brand.dev-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 - name: upload + name: build permissions: contents: read id-token: write @@ -46,6 +46,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run build + run: rye build + - name: Get GitHub OIDC Token id: github-oidc uses: actions/github-script@v6 diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index ce09341..46ad6c7 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash set -exuo pipefail -RESPONSE=$(curl -X POST "$URL" \ +FILENAME=$(basename dist/*.whl) + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ -H "Authorization: Bearer $AUTH" \ -H "Content-Type: application/json") @@ -12,13 +14,13 @@ if [[ "$SIGNED_URL" == "null" ]]; then exit 1 fi -UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ - -H "Content-Type: application/gzip" \ - --data-binary @- "$SIGNED_URL" 2>&1) +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: binary/octet-stream" \ + --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/brand.dev-python/$SHA'\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/brand.dev-python/$SHA/$FILENAME'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 From 92cf85837fb7a56a98736c97d5115308e51c5906 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:06:50 +0000 Subject: [PATCH 03/12] chore(internal): codegen related update --- requirements-dev.lock | 2 +- requirements.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index c39bff6..9fb2ca3 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -56,7 +56,7 @@ httpx==0.28.1 # via brand-dev # via httpx-aiohttp # via respx -httpx-aiohttp==0.1.6 +httpx-aiohttp==0.1.8 # via brand-dev idna==3.4 # via anyio diff --git a/requirements.lock b/requirements.lock index 7b3af9e..073884b 100644 --- a/requirements.lock +++ b/requirements.lock @@ -43,7 +43,7 @@ httpcore==1.0.2 httpx==0.28.1 # via brand-dev # via httpx-aiohttp -httpx-aiohttp==0.1.6 +httpx-aiohttp==0.1.8 # via brand-dev idna==3.4 # via anyio From a9e93bf5b4f7d4d6bf2c82b9e1db113a8396d398 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 02:21:46 +0000 Subject: [PATCH 04/12] chore(internal): bump pinned h11 dep --- requirements-dev.lock | 4 ++-- requirements.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 9fb2ca3..1c0d9f6 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -48,9 +48,9 @@ filelock==3.12.4 frozenlist==1.6.2 # via aiohttp # via aiosignal -h11==0.14.0 +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx httpx==0.28.1 # via brand-dev diff --git a/requirements.lock b/requirements.lock index 073884b..900e4ea 100644 --- a/requirements.lock +++ b/requirements.lock @@ -36,9 +36,9 @@ exceptiongroup==1.2.2 frozenlist==1.6.2 # via aiohttp # via aiosignal -h11==0.14.0 +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx httpx==0.28.1 # via brand-dev From 46005627ab1a6e83e62bb90a8b8f0183b2292786 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 02:41:27 +0000 Subject: [PATCH 05/12] chore(package): mark python 3.13 as supported --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index da0538e..f23cb96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", From 3f1078dede16aed00d8e434b4491f4f3285cfe51 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 02:37:32 +0000 Subject: [PATCH 06/12] fix(parsing): correctly handle nested discriminated unions --- src/brand/dev/_models.py | 13 +++++++----- tests/test_models.py | 45 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/brand/dev/_models.py b/src/brand/dev/_models.py index 4f21498..528d568 100644 --- a/src/brand/dev/_models.py +++ b/src/brand/dev/_models.py @@ -2,9 +2,10 @@ import os import inspect -from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast +from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( + List, Unpack, Literal, ClassVar, @@ -366,7 +367,7 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") - return construct_type(value=value, type_=type_) + return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) def is_basemodel(type_: type) -> bool: @@ -420,7 +421,7 @@ def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: return cast(_T, construct_type(value=value, type_=type_)) -def construct_type(*, value: object, type_: object) -> object: +def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: """Loose coercion to the expected type with construction of nested values. If the given value does not match the expected type then it is returned as-is. @@ -438,8 +439,10 @@ def construct_type(*, value: object, type_: object) -> object: type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(type_): - meta: tuple[Any, ...] = get_args(type_)[1:] + if metadata is not None: + meta: tuple[Any, ...] = tuple(metadata) + elif is_annotated_type(type_): + meta = get_args(type_)[1:] type_ = extract_type_arg(type_, 0) else: meta = tuple() diff --git a/tests/test_models.py b/tests/test_models.py index 3e4688d..d6413aa 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -889,3 +889,48 @@ class ModelB(BaseModel): ) assert isinstance(m, ModelB) + + +def test_nested_discriminated_union() -> None: + class InnerType1(BaseModel): + type: Literal["type_1"] + + class InnerModel(BaseModel): + inner_value: str + + class InnerType2(BaseModel): + type: Literal["type_2"] + some_inner_model: InnerModel + + class Type1(BaseModel): + base_type: Literal["base_type_1"] + value: Annotated[ + Union[ + InnerType1, + InnerType2, + ], + PropertyInfo(discriminator="type"), + ] + + class Type2(BaseModel): + base_type: Literal["base_type_2"] + + T = Annotated[ + Union[ + Type1, + Type2, + ], + PropertyInfo(discriminator="base_type"), + ] + + model = construct_type( + type_=T, + value={ + "base_type": "base_type_1", + "value": { + "type": "type_2", + }, + }, + ) + assert isinstance(model, Type1) + assert isinstance(model.value, InnerType2) From ed9ea71094d6bede408dd145d9951bd5bf24c0b8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 02:55:30 +0000 Subject: [PATCH 07/12] chore(readme): fix version rendering on pypi --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e006b6e..a87e394 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Brand Dev Python API library -[![PyPI version]()](https://pypi.org/project/brand.dev/) + +[![PyPI version](https://img.shields.io/pypi/v/brand.dev.svg?label=pypi%20(stable))](https://pypi.org/project/brand.dev/) The Brand Dev Python library provides convenient access to the Brand Dev REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, From 34c2827853c1d1c04ac05d3ce3fa519179d60793 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 12 Jul 2025 02:02:16 +0000 Subject: [PATCH 08/12] fix(client): don't send Content-Type header on GET requests --- pyproject.toml | 2 +- src/brand/dev/_base_client.py | 11 +++++++++-- tests/test_client.py | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f23cb96..c73c8e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ Homepage = "https://github.com/brand-dot-dev/python-sdk" Repository = "https://github.com/brand-dot-dev/python-sdk" [project.optional-dependencies] -aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] [tool.rye] managed = true diff --git a/src/brand/dev/_base_client.py b/src/brand/dev/_base_client.py index 76be9cc..fcf0f40 100644 --- a/src/brand/dev/_base_client.py +++ b/src/brand/dev/_base_client.py @@ -529,6 +529,15 @@ def _build_request( # work around https://github.com/encode/httpx/discussions/2880 kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + is_body_allowed = options.method.lower() != "get" + + if is_body_allowed: + kwargs["json"] = json_data if is_given(json_data) else None + kwargs["files"] = files + else: + headers.pop("Content-Type", None) + kwargs.pop("data", None) + # TODO: report this error to httpx return self._client.build_request( # pyright: ignore[reportUnknownMemberType] headers=headers, @@ -540,8 +549,6 @@ def _build_request( # so that passing a `TypedDict` doesn't cause an error. # https://github.com/microsoft/pyright/issues/3526#event-6715453066 params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - json=json_data if is_given(json_data) else None, - files=files, **kwargs, ) diff --git a/tests/test_client.py b/tests/test_client.py index 6b13a36..a2b359c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -464,7 +464,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, client: BrandDev) -> None: request = client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, @@ -1269,7 +1269,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, async_client: AsyncBrandDev) -> None: request = async_client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, From 3d8cf3dcad83da7cf75078c501997fb0cfc4eefa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 02:02:18 +0000 Subject: [PATCH 09/12] feat: clean up environment call outs --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index a87e394..40d897e 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,6 @@ pip install brand.dev[aiohttp] Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python -import os import asyncio from brand.dev import DefaultAioHttpClient from brand.dev import AsyncBrandDev @@ -91,7 +90,7 @@ from brand.dev import AsyncBrandDev async def main() -> None: async with AsyncBrandDev( - api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted + api_key="My API Key", http_client=DefaultAioHttpClient(), ) as client: brand = await client.brand.retrieve( From 89a49860aa2c253b9f12397684d7ee38670298b1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 00:41:02 +0000 Subject: [PATCH 10/12] feat(api): manual updates --- .stats.yml | 6 +- api.md | 2 - src/brand/dev/resources/brand.py | 110 ------------------ src/brand/dev/types/__init__.py | 2 - ...rand_identify_from_transaction_response.py | 12 -- .../brand_retrieve_by_ticker_response.py | 12 -- .../dev/types/brand_retrieve_response.py | 16 --- src/brand/dev/types/brand_search_params.py | 21 ---- src/brand/dev/types/brand_search_response.py | 22 ---- tests/api_resources/test_brand.py | 87 -------------- 10 files changed, 3 insertions(+), 287 deletions(-) delete mode 100644 src/brand/dev/types/brand_search_params.py delete mode 100644 src/brand/dev/types/brand_search_response.py diff --git a/.stats.yml b/.stats.yml index b3fbada..7daf4a5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 10 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-aff48154fa37f0eb293cf660842ceab35c597509aee08f6b76df066828229c58.yml -openapi_spec_hash: a8ade5d7246da14e2ff161e829d11c12 +configured_endpoints: 9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-70f44e886c51bd700af031ad9b5c8f0042ef15fde038ba83ed08f61cd9d05266.yml +openapi_spec_hash: 9b834ba9e373689a8e2fbd8312b1f2de config_hash: 8f3ee44d690a305369555016a77ed016 diff --git a/api.md b/api.md index da93d3d..ef7c6cc 100644 --- a/api.md +++ b/api.md @@ -12,7 +12,6 @@ from brand.dev.types import ( BrandRetrieveNaicsResponse, BrandRetrieveSimplifiedResponse, BrandScreenshotResponse, - BrandSearchResponse, BrandStyleguideResponse, ) ``` @@ -27,5 +26,4 @@ Methods: - client.brand.retrieve_naics(\*\*params) -> BrandRetrieveNaicsResponse - client.brand.retrieve_simplified(\*\*params) -> BrandRetrieveSimplifiedResponse - client.brand.screenshot(\*\*params) -> BrandScreenshotResponse -- client.brand.search(\*\*params) -> BrandSearchResponse - client.brand.styleguide(\*\*params) -> BrandStyleguideResponse diff --git a/src/brand/dev/resources/brand.py b/src/brand/dev/resources/brand.py index f30f7cf..58a3116 100644 --- a/src/brand/dev/resources/brand.py +++ b/src/brand/dev/resources/brand.py @@ -8,7 +8,6 @@ import httpx from ..types import ( - brand_search_params, brand_ai_query_params, brand_prefetch_params, brand_retrieve_params, @@ -30,7 +29,6 @@ async_to_streamed_response_wrapper, ) from .._base_client import make_request_options -from ..types.brand_search_response import BrandSearchResponse from ..types.brand_ai_query_response import BrandAIQueryResponse from ..types.brand_prefetch_response import BrandPrefetchResponse from ..types.brand_retrieve_response import BrandRetrieveResponse @@ -530,54 +528,6 @@ def screenshot( cast_to=BrandScreenshotResponse, ) - def search( - self, - *, - query: str, - timeout_ms: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> BrandSearchResponse: - """ - Search brands by query - - Args: - query: Query string to search brands - - timeout_ms: Optional timeout in milliseconds for the request. If the request takes longer - than this value, it will be aborted with a 408 status code. Maximum allowed - value is 300000ms (5 minutes). - - 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, - "timeout_ms": timeout_ms, - }, - brand_search_params.BrandSearchParams, - ), - ), - cast_to=BrandSearchResponse, - ) - def styleguide( self, *, @@ -1116,54 +1066,6 @@ async def screenshot( cast_to=BrandScreenshotResponse, ) - async def search( - self, - *, - query: str, - timeout_ms: int | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> BrandSearchResponse: - """ - Search brands by query - - Args: - query: Query string to search brands - - timeout_ms: Optional timeout in milliseconds for the request. If the request takes longer - than this value, it will be aborted with a 408 status code. Maximum allowed - value is 300000ms (5 minutes). - - 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, - "timeout_ms": timeout_ms, - }, - brand_search_params.BrandSearchParams, - ), - ), - cast_to=BrandSearchResponse, - ) - async def styleguide( self, *, @@ -1244,9 +1146,6 @@ def __init__(self, brand: BrandResource) -> None: self.screenshot = to_raw_response_wrapper( brand.screenshot, ) - self.search = to_raw_response_wrapper( - brand.search, - ) self.styleguide = to_raw_response_wrapper( brand.styleguide, ) @@ -1280,9 +1179,6 @@ def __init__(self, brand: AsyncBrandResource) -> None: self.screenshot = async_to_raw_response_wrapper( brand.screenshot, ) - self.search = async_to_raw_response_wrapper( - brand.search, - ) self.styleguide = async_to_raw_response_wrapper( brand.styleguide, ) @@ -1316,9 +1212,6 @@ def __init__(self, brand: BrandResource) -> None: self.screenshot = to_streamed_response_wrapper( brand.screenshot, ) - self.search = to_streamed_response_wrapper( - brand.search, - ) self.styleguide = to_streamed_response_wrapper( brand.styleguide, ) @@ -1352,9 +1245,6 @@ def __init__(self, brand: AsyncBrandResource) -> None: self.screenshot = async_to_streamed_response_wrapper( brand.screenshot, ) - self.search = async_to_streamed_response_wrapper( - brand.search, - ) self.styleguide = async_to_streamed_response_wrapper( brand.styleguide, ) diff --git a/src/brand/dev/types/__init__.py b/src/brand/dev/types/__init__.py index c7428ce..35536b0 100644 --- a/src/brand/dev/types/__init__.py +++ b/src/brand/dev/types/__init__.py @@ -2,11 +2,9 @@ from __future__ import annotations -from .brand_search_params import BrandSearchParams as BrandSearchParams from .brand_ai_query_params import BrandAIQueryParams as BrandAIQueryParams from .brand_prefetch_params import BrandPrefetchParams as BrandPrefetchParams from .brand_retrieve_params import BrandRetrieveParams as BrandRetrieveParams -from .brand_search_response import BrandSearchResponse as BrandSearchResponse from .brand_ai_query_response import BrandAIQueryResponse as BrandAIQueryResponse from .brand_prefetch_response import BrandPrefetchResponse as BrandPrefetchResponse from .brand_retrieve_response import BrandRetrieveResponse as BrandRetrieveResponse diff --git a/src/brand/dev/types/brand_identify_from_transaction_response.py b/src/brand/dev/types/brand_identify_from_transaction_response.py index 48411d6..a48a4df 100644 --- a/src/brand/dev/types/brand_identify_from_transaction_response.py +++ b/src/brand/dev/types/brand_identify_from_transaction_response.py @@ -12,7 +12,6 @@ "BrandBackdropColor", "BrandBackdropResolution", "BrandColor", - "BrandFont", "BrandLogo", "BrandLogoColor", "BrandLogoResolution", @@ -79,14 +78,6 @@ class BrandColor(BaseModel): """Name of the color""" -class BrandFont(BaseModel): - name: Optional[str] = None - """Name of the font""" - - usage: Optional[str] = None - """Usage of the font, e.g., 'title', 'body', 'button'""" - - class BrandLogoColor(BaseModel): hex: Optional[str] = None """Color in hexadecimal format""" @@ -152,9 +143,6 @@ class Brand(BaseModel): domain: Optional[str] = None """The domain name of the brand""" - fonts: Optional[List[BrandFont]] = None - """An array of fonts used by the brand's website""" - logos: Optional[List[BrandLogo]] = None """An array of logos associated with the brand""" diff --git a/src/brand/dev/types/brand_retrieve_by_ticker_response.py b/src/brand/dev/types/brand_retrieve_by_ticker_response.py index 9da5d28..fb0cfce 100644 --- a/src/brand/dev/types/brand_retrieve_by_ticker_response.py +++ b/src/brand/dev/types/brand_retrieve_by_ticker_response.py @@ -12,7 +12,6 @@ "BrandBackdropColor", "BrandBackdropResolution", "BrandColor", - "BrandFont", "BrandLogo", "BrandLogoColor", "BrandLogoResolution", @@ -79,14 +78,6 @@ class BrandColor(BaseModel): """Name of the color""" -class BrandFont(BaseModel): - name: Optional[str] = None - """Name of the font""" - - usage: Optional[str] = None - """Usage of the font, e.g., 'title', 'body', 'button'""" - - class BrandLogoColor(BaseModel): hex: Optional[str] = None """Color in hexadecimal format""" @@ -152,9 +143,6 @@ class Brand(BaseModel): domain: Optional[str] = None """The domain name of the brand""" - fonts: Optional[List[BrandFont]] = None - """An array of fonts used by the brand's website""" - logos: Optional[List[BrandLogo]] = None """An array of logos associated with the brand""" diff --git a/src/brand/dev/types/brand_retrieve_response.py b/src/brand/dev/types/brand_retrieve_response.py index 426b99c..32f2115 100644 --- a/src/brand/dev/types/brand_retrieve_response.py +++ b/src/brand/dev/types/brand_retrieve_response.py @@ -12,7 +12,6 @@ "BrandBackdropColor", "BrandBackdropResolution", "BrandColor", - "BrandFont", "BrandLogo", "BrandLogoColor", "BrandLogoResolution", @@ -79,14 +78,6 @@ class BrandColor(BaseModel): """Name of the color""" -class BrandFont(BaseModel): - name: Optional[str] = None - """Name of the font""" - - usage: Optional[str] = None - """Usage of the font, e.g., 'title', 'body', 'button'""" - - class BrandLogoColor(BaseModel): hex: Optional[str] = None """Color in hexadecimal format""" @@ -152,13 +143,6 @@ class Brand(BaseModel): domain: Optional[str] = None """The domain name of the brand""" - fonts: Optional[List[BrandFont]] = None - """An array of fonts used by the brand's website. - - NOTE: This is deprecated and will be removed in the future. Please migrate to - the styleguide API. - """ - logos: Optional[List[BrandLogo]] = None """An array of logos associated with the brand""" diff --git a/src/brand/dev/types/brand_search_params.py b/src/brand/dev/types/brand_search_params.py deleted file mode 100644 index 2541682..0000000 --- a/src/brand/dev/types/brand_search_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__ = ["BrandSearchParams"] - - -class BrandSearchParams(TypedDict, total=False): - query: Required[str] - """Query string to search brands""" - - timeout_ms: Annotated[int, PropertyInfo(alias="timeoutMS")] - """Optional timeout in milliseconds for the request. - - If the request takes longer than this value, it will be aborted with a 408 - status code. Maximum allowed value is 300000ms (5 minutes). - """ diff --git a/src/brand/dev/types/brand_search_response.py b/src/brand/dev/types/brand_search_response.py deleted file mode 100644 index c1c30b3..0000000 --- a/src/brand/dev/types/brand_search_response.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import TypeAlias - -from .._models import BaseModel - -__all__ = ["BrandSearchResponse", "BrandSearchResponseItem"] - - -class BrandSearchResponseItem(BaseModel): - domain: Optional[str] = None - """Domain name of the brand""" - - logo: Optional[str] = None - """URL of the brand's logo""" - - title: Optional[str] = None - """Title or name of the brand""" - - -BrandSearchResponse: TypeAlias = List[BrandSearchResponseItem] diff --git a/tests/api_resources/test_brand.py b/tests/api_resources/test_brand.py index 4814262..571963c 100644 --- a/tests/api_resources/test_brand.py +++ b/tests/api_resources/test_brand.py @@ -10,7 +10,6 @@ from brand.dev import BrandDev, AsyncBrandDev from tests.utils import assert_matches_type from brand.dev.types import ( - BrandSearchResponse, BrandAIQueryResponse, BrandPrefetchResponse, BrandRetrieveResponse, @@ -416,49 +415,6 @@ def test_streaming_response_screenshot(self, client: BrandDev) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip() - @parametrize - def test_method_search(self, client: BrandDev) -> None: - brand = client.brand.search( - query="query", - ) - assert_matches_type(BrandSearchResponse, brand, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_method_search_with_all_params(self, client: BrandDev) -> None: - brand = client.brand.search( - query="query", - timeout_ms=1, - ) - assert_matches_type(BrandSearchResponse, brand, path=["response"]) - - @pytest.mark.skip() - @parametrize - def test_raw_response_search(self, client: BrandDev) -> None: - response = client.brand.with_raw_response.search( - query="query", - ) - - 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() - @parametrize - def test_streaming_response_search(self, client: BrandDev) -> None: - with client.brand.with_streaming_response.search( - query="query", - ) 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 - @pytest.mark.skip() @parametrize def test_method_styleguide(self, client: BrandDev) -> None: @@ -896,49 +852,6 @@ async def test_streaming_response_screenshot(self, async_client: AsyncBrandDev) assert cast(Any, response.is_closed) is True - @pytest.mark.skip() - @parametrize - async def test_method_search(self, async_client: AsyncBrandDev) -> None: - brand = await async_client.brand.search( - query="query", - ) - assert_matches_type(BrandSearchResponse, brand, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_method_search_with_all_params(self, async_client: AsyncBrandDev) -> None: - brand = await async_client.brand.search( - query="query", - timeout_ms=1, - ) - assert_matches_type(BrandSearchResponse, brand, path=["response"]) - - @pytest.mark.skip() - @parametrize - async def test_raw_response_search(self, async_client: AsyncBrandDev) -> None: - response = await async_client.brand.with_raw_response.search( - query="query", - ) - - 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() - @parametrize - async def test_streaming_response_search(self, async_client: AsyncBrandDev) -> None: - async with async_client.brand.with_streaming_response.search( - query="query", - ) 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 - @pytest.mark.skip() @parametrize async def test_method_styleguide(self, async_client: AsyncBrandDev) -> None: From f7edb59816b1aaf960f79db3b6a14e16cd54d399 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 00:41:21 +0000 Subject: [PATCH 11/12] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 7daf4a5..2a58fb8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 9 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-70f44e886c51bd700af031ad9b5c8f0042ef15fde038ba83ed08f61cd9d05266.yml openapi_spec_hash: 9b834ba9e373689a8e2fbd8312b1f2de -config_hash: 8f3ee44d690a305369555016a77ed016 +config_hash: 4b10254ea5b8e26ce632222b94a918aa From 72e3e3885917fa875b39cac7161659ee59d1692f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 00:41:36 +0000 Subject: [PATCH 12/12] release: 1.10.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 25 +++++++++++++++++++++++++ pyproject.toml | 2 +- src/brand/dev/_version.py | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c3c9552..eb4e0db 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.9.0" + ".": "1.10.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 102bef7..a91c750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 1.10.0 (2025-07-21) + +Full Changelog: [v1.9.0...v1.10.0](https://github.com/brand-dot-dev/python-sdk/compare/v1.9.0...v1.10.0) + +### Features + +* **api:** manual updates ([89a4986](https://github.com/brand-dot-dev/python-sdk/commit/89a49860aa2c253b9f12397684d7ee38670298b1)) +* clean up environment call outs ([3d8cf3d](https://github.com/brand-dot-dev/python-sdk/commit/3d8cf3dcad83da7cf75078c501997fb0cfc4eefa)) + + +### Bug Fixes + +* **ci:** correct conditional ([ad26494](https://github.com/brand-dot-dev/python-sdk/commit/ad26494daca49a55899f9e769e9b38e20f51857a)) +* **client:** don't send Content-Type header on GET requests ([34c2827](https://github.com/brand-dot-dev/python-sdk/commit/34c2827853c1d1c04ac05d3ce3fa519179d60793)) +* **parsing:** correctly handle nested discriminated unions ([3f1078d](https://github.com/brand-dot-dev/python-sdk/commit/3f1078dede16aed00d8e434b4491f4f3285cfe51)) + + +### Chores + +* **ci:** change upload type ([9f67ed0](https://github.com/brand-dot-dev/python-sdk/commit/9f67ed039e0b905f81d8c1e1a1bd79e9c997d483)) +* **internal:** bump pinned h11 dep ([a9e93bf](https://github.com/brand-dot-dev/python-sdk/commit/a9e93bf5b4f7d4d6bf2c82b9e1db113a8396d398)) +* **internal:** codegen related update ([92cf858](https://github.com/brand-dot-dev/python-sdk/commit/92cf85837fb7a56a98736c97d5115308e51c5906)) +* **package:** mark python 3.13 as supported ([4600562](https://github.com/brand-dot-dev/python-sdk/commit/46005627ab1a6e83e62bb90a8b8f0183b2292786)) +* **readme:** fix version rendering on pypi ([ed9ea71](https://github.com/brand-dot-dev/python-sdk/commit/ed9ea71094d6bede408dd145d9951bd5bf24c0b8)) + ## 1.9.0 (2025-06-29) Full Changelog: [v1.8.0...v1.9.0](https://github.com/brand-dot-dev/python-sdk/compare/v1.8.0...v1.9.0) diff --git a/pyproject.toml b/pyproject.toml index c73c8e1..2e2b992 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "brand.dev" -version = "1.9.0" +version = "1.10.0" description = "The official Python library for the brand.dev API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/brand/dev/_version.py b/src/brand/dev/_version.py index 94cbe8c..46e2f07 100644 --- a/src/brand/dev/_version.py +++ b/src/brand/dev/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "brand.dev" -__version__ = "1.9.0" # x-release-please-version +__version__ = "1.10.0" # x-release-please-version