Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.22.0"
".": "1.23.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 12
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-fff3572a2d6f3a8461fbf52fb74882e1f4ae4a2b31a75673dcae230b336911d2.yml
openapi_spec_hash: b04ce3c7879b31f1e38cd76372e8e652
config_hash: 86160e220c81f47769a71c9343e486d8
configured_endpoints: 13
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-f69782c2c4296df9db6b41a3a7359a9e4910f59e34901b9f0e8045cec3f9ca69.yml
openapi_spec_hash: f06c3956a6fc7e57614b120910339747
config_hash: 6aaf0fe6f8877c9c5d9af95597123cb4
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Changelog

## 1.23.0 (2025-11-29)

Full Changelog: [v1.22.0...v1.23.0](https://github.com/brand-dot-dev/python-sdk/compare/v1.22.0...v1.23.0)

### Features

* **api:** manual updates ([d95285a](https://github.com/brand-dot-dev/python-sdk/commit/d95285ae339e8df4d50e793e7c9938ac226974f1))


### Bug Fixes

* ensure streams are always closed ([77df827](https://github.com/brand-dot-dev/python-sdk/commit/77df827c2608b4326d707c0ecbc93d7ec83957d5))


### Chores

* **deps:** mypy 1.18.1 has a regression, pin to 1.17 ([eedd772](https://github.com/brand-dot-dev/python-sdk/commit/eedd772cb757bcff196b6ed21ac9e887b8423fe0))

## 1.22.0 (2025-11-24)

Full Changelog: [v1.21.0...v1.22.0](https://github.com/brand-dot-dev/python-sdk/compare/v1.21.0...v1.22.0)
Expand Down
2 changes: 2 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Types:
from brand.dev.types import (
BrandRetrieveResponse,
BrandAIQueryResponse,
BrandFontsResponse,
BrandIdentifyFromTransactionResponse,
BrandPrefetchResponse,
BrandRetrieveByEmailResponse,
Expand All @@ -23,6 +24,7 @@ Methods:

- <code title="get /brand/retrieve">client.brand.<a href="./src/brand/dev/resources/brand.py">retrieve</a>(\*\*<a href="src/brand/dev/types/brand_retrieve_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_retrieve_response.py">BrandRetrieveResponse</a></code>
- <code title="post /brand/ai/query">client.brand.<a href="./src/brand/dev/resources/brand.py">ai_query</a>(\*\*<a href="src/brand/dev/types/brand_ai_query_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_ai_query_response.py">BrandAIQueryResponse</a></code>
- <code title="get /brand/fonts">client.brand.<a href="./src/brand/dev/resources/brand.py">fonts</a>(\*\*<a href="src/brand/dev/types/brand_fonts_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_fonts_response.py">BrandFontsResponse</a></code>
- <code title="get /brand/transaction_identifier">client.brand.<a href="./src/brand/dev/resources/brand.py">identify_from_transaction</a>(\*\*<a href="src/brand/dev/types/brand_identify_from_transaction_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_identify_from_transaction_response.py">BrandIdentifyFromTransactionResponse</a></code>
- <code title="post /brand/prefetch">client.brand.<a href="./src/brand/dev/resources/brand.py">prefetch</a>(\*\*<a href="src/brand/dev/types/brand_prefetch_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_prefetch_response.py">BrandPrefetchResponse</a></code>
- <code title="get /brand/retrieve-by-email">client.brand.<a href="./src/brand/dev/resources/brand.py">retrieve_by_email</a>(\*\*<a href="src/brand/dev/types/brand_retrieve_by_email_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_retrieve_by_email_response.py">BrandRetrieveByEmailResponse</a></code>
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "brand.dev"
version = "1.22.0"
version = "1.23.0"
description = "The official Python library for the brand.dev API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down Expand Up @@ -46,7 +46,7 @@ managed = true
# version pins are in requirements-dev.lock
dev-dependencies = [
"pyright==1.1.399",
"mypy",
"mypy==1.17",
"respx",
"pytest",
"pytest-asyncio",
Expand Down
4 changes: 3 additions & 1 deletion requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ mdurl==0.1.2
multidict==6.4.4
# via aiohttp
# via yarl
mypy==1.14.1
mypy==1.17.0
mypy-extensions==1.0.0
# via mypy
nodeenv==1.8.0
Expand All @@ -81,6 +81,8 @@ nox==2023.4.22
packaging==23.2
# via nox
# via pytest
pathspec==0.12.1
# via mypy
platformdirs==3.11.0
# via virtualenv
pluggy==1.5.0
Expand Down
8 changes: 4 additions & 4 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,21 @@ multidict==6.4.4
propcache==0.3.1
# via aiohttp
# via yarl
pydantic==2.11.9
pydantic==2.12.5
# via brand-dev
pydantic-core==2.33.2
pydantic-core==2.41.5
# via pydantic
sniffio==1.3.0
# via anyio
# via brand-dev
typing-extensions==4.12.2
typing-extensions==4.15.0
# via anyio
# via brand-dev
# via multidict
# via pydantic
# via pydantic-core
# via typing-inspection
typing-inspection==0.4.1
typing-inspection==0.4.2
# via pydantic
yarl==1.20.0
# via aiohttp
22 changes: 12 additions & 10 deletions src/brand/dev/_streaming.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ def __stream__(self) -> Iterator[_T]:
process_data = self._client._process_response_data
iterator = self._iter_events()

for sse in iterator:
yield process_data(data=sse.json(), cast_to=cast_to, response=response)

# As we might not fully consume the response stream, we need to close it explicitly
response.close()
try:
for sse in iterator:
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
finally:
# Ensure the response is closed even if the consumer doesn't read all data
response.close()

def __enter__(self) -> Self:
return self
Expand Down Expand Up @@ -117,11 +118,12 @@ async def __stream__(self) -> AsyncIterator[_T]:
process_data = self._client._process_response_data
iterator = self._iter_events()

async for sse in iterator:
yield process_data(data=sse.json(), cast_to=cast_to, response=response)

# As we might not fully consume the response stream, we need to close it explicitly
await response.aclose()
try:
async for sse in iterator:
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
finally:
# Ensure the response is closed even if the consumer doesn't read all data
await response.aclose()

async def __aenter__(self) -> Self:
return self
Expand Down
2 changes: 1 addition & 1 deletion src/brand/dev/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "brand.dev"
__version__ = "1.22.0" # x-release-please-version
__version__ = "1.23.0" # x-release-please-version
114 changes: 114 additions & 0 deletions src/brand/dev/resources/brand.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import httpx

from ..types import (
brand_fonts_params,
brand_ai_query_params,
brand_prefetch_params,
brand_retrieve_params,
Expand All @@ -32,6 +33,7 @@
async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
from ..types.brand_fonts_response import BrandFontsResponse
from ..types.brand_ai_query_response import BrandAIQueryResponse
from ..types.brand_prefetch_response import BrandPrefetchResponse
from ..types.brand_retrieve_response import BrandRetrieveResponse
Expand Down Expand Up @@ -239,6 +241,56 @@ def ai_query(
cast_to=BrandAIQueryResponse,
)

def fonts(
self,
*,
domain: str,
timeout_ms: int | 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,
) -> BrandFontsResponse:
"""
Beta feature: Extract font information from a brand's website including font
families, usage statistics, fallbacks, and element/word counts.

Args:
domain: Domain name to extract fonts from (e.g., 'example.com', 'google.com'). The
domain will be automatically normalized and validated.

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/fonts",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=maybe_transform(
{
"domain": domain,
"timeout_ms": timeout_ms,
},
brand_fonts_params.BrandFontsParams,
),
),
cast_to=BrandFontsResponse,
)

def identify_from_transaction(
self,
*,
Expand Down Expand Up @@ -1612,6 +1664,56 @@ async def ai_query(
cast_to=BrandAIQueryResponse,
)

async def fonts(
self,
*,
domain: str,
timeout_ms: int | 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,
) -> BrandFontsResponse:
"""
Beta feature: Extract font information from a brand's website including font
families, usage statistics, fallbacks, and element/word counts.

Args:
domain: Domain name to extract fonts from (e.g., 'example.com', 'google.com'). The
domain will be automatically normalized and validated.

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/fonts",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=await async_maybe_transform(
{
"domain": domain,
"timeout_ms": timeout_ms,
},
brand_fonts_params.BrandFontsParams,
),
),
cast_to=BrandFontsResponse,
)

async def identify_from_transaction(
self,
*,
Expand Down Expand Up @@ -2804,6 +2906,9 @@ def __init__(self, brand: BrandResource) -> None:
self.ai_query = to_raw_response_wrapper(
brand.ai_query,
)
self.fonts = to_raw_response_wrapper(
brand.fonts,
)
self.identify_from_transaction = to_raw_response_wrapper(
brand.identify_from_transaction,
)
Expand Down Expand Up @@ -2846,6 +2951,9 @@ def __init__(self, brand: AsyncBrandResource) -> None:
self.ai_query = async_to_raw_response_wrapper(
brand.ai_query,
)
self.fonts = async_to_raw_response_wrapper(
brand.fonts,
)
self.identify_from_transaction = async_to_raw_response_wrapper(
brand.identify_from_transaction,
)
Expand Down Expand Up @@ -2888,6 +2996,9 @@ def __init__(self, brand: BrandResource) -> None:
self.ai_query = to_streamed_response_wrapper(
brand.ai_query,
)
self.fonts = to_streamed_response_wrapper(
brand.fonts,
)
self.identify_from_transaction = to_streamed_response_wrapper(
brand.identify_from_transaction,
)
Expand Down Expand Up @@ -2930,6 +3041,9 @@ def __init__(self, brand: AsyncBrandResource) -> None:
self.ai_query = async_to_streamed_response_wrapper(
brand.ai_query,
)
self.fonts = async_to_streamed_response_wrapper(
brand.fonts,
)
self.identify_from_transaction = async_to_streamed_response_wrapper(
brand.identify_from_transaction,
)
Expand Down
2 changes: 2 additions & 0 deletions src/brand/dev/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

from .brand_fonts_params import BrandFontsParams as BrandFontsParams
from .brand_fonts_response import BrandFontsResponse as BrandFontsResponse
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
Expand Down
24 changes: 24 additions & 0 deletions src/brand/dev/types/brand_fonts_params.py
Original file line number Diff line number Diff line change
@@ -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, Annotated, TypedDict

from .._utils import PropertyInfo

__all__ = ["BrandFontsParams"]


class BrandFontsParams(TypedDict, total=False):
domain: Required[str]
"""Domain name to extract fonts from (e.g., 'example.com', 'google.com').

The domain will be automatically normalized and validated.
"""

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).
"""
Loading