diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 8255acf..69eb19a 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "1.19.1"
+ ".": "1.20.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 26179c7..561a7a7 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 11
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-6620330945de41f1c453692af40842f08fe1fd281ff6ba4e79d447c941ebd783.yml
-openapi_spec_hash: 861a43669d27d942d4bd3e36a398e95b
-config_hash: 083e432ea397a9018371145493400188
+configured_endpoints: 12
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-070cac50467cd07e8601e948fc97e3c82ea0630d6a0b0f24164335e396893e6a.yml
+openapi_spec_hash: b887bcfe688f72b3a34ee24246d12955
+config_hash: 86160e220c81f47769a71c9343e486d8
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66d9387..1ef695c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,24 @@
# Changelog
+## 1.20.0 (2025-11-19)
+
+Full Changelog: [v1.19.1...v1.20.0](https://github.com/brand-dot-dev/python-sdk/compare/v1.19.1...v1.20.0)
+
+### Features
+
+* **api:** manual updates ([152e848](https://github.com/brand-dot-dev/python-sdk/commit/152e8489b6ecbbe717d48ac0c437e88c64e923a5))
+
+
+### Bug Fixes
+
+* compat with Python 3.14 ([8602245](https://github.com/brand-dot-dev/python-sdk/commit/860224506b4fe79750cff976b1bed305f4f826da))
+* **compat:** update signatures of `model_dump` and `model_dump_json` for Pydantic v1 ([768e2d1](https://github.com/brand-dot-dev/python-sdk/commit/768e2d13ddf92adde07ad4715419caa4b3257338))
+
+
+### Chores
+
+* **package:** drop Python 3.8 support ([ecc46d0](https://github.com/brand-dot-dev/python-sdk/commit/ecc46d081a6d8ecbbdb633e444218f0d12487f2b))
+
## 1.19.1 (2025-11-04)
Full Changelog: [v1.19.0...v1.19.1](https://github.com/brand-dot-dev/python-sdk/compare/v1.19.0...v1.19.1)
diff --git a/README.md b/README.md
index 41e137d..5ee938a 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[)](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+
+The Brand Dev Python library provides convenient access to the Brand Dev REST API from any Python 3.9+
application. The library includes type definitions for all request params and response fields,
and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).
@@ -396,7 +396,7 @@ print(brand.dev.__version__)
## Requirements
-Python 3.8 or higher.
+Python 3.9 or higher.
## Contributing
diff --git a/api.md b/api.md
index cec128a..cd8c7b2 100644
--- a/api.md
+++ b/api.md
@@ -9,6 +9,7 @@ from brand.dev.types import (
BrandIdentifyFromTransactionResponse,
BrandPrefetchResponse,
BrandRetrieveByEmailResponse,
+ BrandRetrieveByIsinResponse,
BrandRetrieveByNameResponse,
BrandRetrieveByTickerResponse,
BrandRetrieveNaicsResponse,
@@ -25,6 +26,7 @@ Methods:
- client.brand.identify_from_transaction(\*\*params) -> BrandIdentifyFromTransactionResponse
- client.brand.prefetch(\*\*params) -> BrandPrefetchResponse
- client.brand.retrieve_by_email(\*\*params) -> BrandRetrieveByEmailResponse
+- client.brand.retrieve_by_isin(\*\*params) -> BrandRetrieveByIsinResponse
- client.brand.retrieve_by_name(\*\*params) -> BrandRetrieveByNameResponse
- client.brand.retrieve_by_ticker(\*\*params) -> BrandRetrieveByTickerResponse
- client.brand.retrieve_naics(\*\*params) -> BrandRetrieveNaicsResponse
diff --git a/pyproject.toml b/pyproject.toml
index 8541931..5667b40 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "brand.dev"
-version = "1.19.1"
+version = "1.20.0"
description = "The official Python library for the brand.dev API"
dynamic = ["readme"]
license = "Apache-2.0"
@@ -15,11 +15,10 @@ dependencies = [
"distro>=1.7.0, <2",
"sniffio",
]
-requires-python = ">= 3.8"
+requires-python = ">= 3.9"
classifiers = [
"Typing :: Typed",
"Intended Audience :: Developers",
- "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
@@ -141,7 +140,7 @@ filterwarnings = [
# there are a couple of flags that are still disabled by
# default in strict mode as they are experimental and niche.
typeCheckingMode = "strict"
-pythonVersion = "3.8"
+pythonVersion = "3.9"
exclude = [
"_dev",
diff --git a/src/brand/dev/_models.py b/src/brand/dev/_models.py
index 6a3cd1d..ca9500b 100644
--- a/src/brand/dev/_models.py
+++ b/src/brand/dev/_models.py
@@ -2,6 +2,7 @@
import os
import inspect
+import weakref
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
from datetime import date, datetime
from typing_extensions import (
@@ -256,15 +257,16 @@ def model_dump(
mode: Literal["json", "python"] | str = "python",
include: IncEx | None = None,
exclude: IncEx | None = None,
+ context: Any | None = None,
by_alias: bool | None = None,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
+ exclude_computed_fields: bool = False,
round_trip: bool = False,
warnings: bool | Literal["none", "warn", "error"] = True,
- context: dict[str, Any] | None = None,
- serialize_as_any: bool = False,
fallback: Callable[[Any], Any] | None = None,
+ serialize_as_any: bool = False,
) -> dict[str, Any]:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump
@@ -272,16 +274,24 @@ def model_dump(
Args:
mode: The mode in which `to_python` should run.
- If mode is 'json', the dictionary will only contain JSON serializable types.
- If mode is 'python', the dictionary may contain any Python objects.
- include: A list of fields to include in the output.
- exclude: A list of fields to exclude from the output.
+ If mode is 'json', the output will only contain JSON serializable types.
+ If mode is 'python', the output may contain non-JSON-serializable Python objects.
+ include: A set of fields to include in the output.
+ exclude: A set of fields to exclude from the output.
+ context: Additional context to pass to the serializer.
by_alias: Whether to use the field's alias in the dictionary key if defined.
- exclude_unset: Whether to exclude fields that are unset or None from the output.
- exclude_defaults: Whether to exclude fields that are set to their default value from the output.
- exclude_none: Whether to exclude fields that have a value of `None` from the output.
- round_trip: Whether to enable serialization and deserialization round-trip support.
- warnings: Whether to log warnings when invalid fields are encountered.
+ exclude_unset: Whether to exclude fields that have not been explicitly set.
+ exclude_defaults: Whether to exclude fields that are set to their default value.
+ exclude_none: Whether to exclude fields that have a value of `None`.
+ exclude_computed_fields: Whether to exclude computed fields.
+ While this can be useful for round-tripping, it is usually recommended to use the dedicated
+ `round_trip` parameter instead.
+ round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T].
+ warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors,
+ "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError].
+ fallback: A function to call when an unknown value is encountered. If not provided,
+ a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised.
+ serialize_as_any: Whether to serialize fields with duck-typing serialization behavior.
Returns:
A dictionary representation of the model.
@@ -298,6 +308,8 @@ def model_dump(
raise ValueError("serialize_as_any is only supported in Pydantic v2")
if fallback is not None:
raise ValueError("fallback is only supported in Pydantic v2")
+ if exclude_computed_fields != False:
+ raise ValueError("exclude_computed_fields is only supported in Pydantic v2")
dumped = super().dict( # pyright: ignore[reportDeprecated]
include=include,
exclude=exclude,
@@ -314,15 +326,17 @@ def model_dump_json(
self,
*,
indent: int | None = None,
+ ensure_ascii: bool = False,
include: IncEx | None = None,
exclude: IncEx | None = None,
+ context: Any | None = None,
by_alias: bool | None = None,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
+ exclude_computed_fields: bool = False,
round_trip: bool = False,
warnings: bool | Literal["none", "warn", "error"] = True,
- context: dict[str, Any] | None = None,
fallback: Callable[[Any], Any] | None = None,
serialize_as_any: bool = False,
) -> str:
@@ -354,6 +368,10 @@ def model_dump_json(
raise ValueError("serialize_as_any is only supported in Pydantic v2")
if fallback is not None:
raise ValueError("fallback is only supported in Pydantic v2")
+ if ensure_ascii != False:
+ raise ValueError("ensure_ascii is only supported in Pydantic v2")
+ if exclude_computed_fields != False:
+ raise ValueError("exclude_computed_fields is only supported in Pydantic v2")
return super().json( # type: ignore[reportDeprecated]
indent=indent,
include=include,
@@ -573,6 +591,9 @@ class CachedDiscriminatorType(Protocol):
__discriminator__: DiscriminatorDetails
+DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary()
+
+
class DiscriminatorDetails:
field_name: str
"""The name of the discriminator field in the variant class, e.g.
@@ -615,8 +636,9 @@ def __init__(
def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None:
- if isinstance(union, CachedDiscriminatorType):
- return union.__discriminator__
+ cached = DISCRIMINATOR_CACHE.get(union)
+ if cached is not None:
+ return cached
discriminator_field_name: str | None = None
@@ -669,7 +691,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any,
discriminator_field=discriminator_field_name,
discriminator_alias=discriminator_alias,
)
- cast(CachedDiscriminatorType, union).__discriminator__ = details
+ DISCRIMINATOR_CACHE.setdefault(union, details)
return details
diff --git a/src/brand/dev/_utils/_sync.py b/src/brand/dev/_utils/_sync.py
index ad7ec71..f6027c1 100644
--- a/src/brand/dev/_utils/_sync.py
+++ b/src/brand/dev/_utils/_sync.py
@@ -1,10 +1,8 @@
from __future__ import annotations
-import sys
import asyncio
import functools
-import contextvars
-from typing import Any, TypeVar, Callable, Awaitable
+from typing import TypeVar, Callable, Awaitable
from typing_extensions import ParamSpec
import anyio
@@ -15,34 +13,11 @@
T_ParamSpec = ParamSpec("T_ParamSpec")
-if sys.version_info >= (3, 9):
- _asyncio_to_thread = asyncio.to_thread
-else:
- # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
- # for Python 3.8 support
- async def _asyncio_to_thread(
- func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
- ) -> Any:
- """Asynchronously run function *func* in a separate thread.
-
- Any *args and **kwargs supplied for this function are directly passed
- to *func*. Also, the current :class:`contextvars.Context` is propagated,
- allowing context variables from the main thread to be accessed in the
- separate thread.
-
- Returns a coroutine that can be awaited to get the eventual result of *func*.
- """
- loop = asyncio.events.get_running_loop()
- ctx = contextvars.copy_context()
- func_call = functools.partial(ctx.run, func, *args, **kwargs)
- return await loop.run_in_executor(None, func_call)
-
-
async def to_thread(
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
) -> T_Retval:
if sniffio.current_async_library() == "asyncio":
- return await _asyncio_to_thread(func, *args, **kwargs)
+ return await asyncio.to_thread(func, *args, **kwargs)
return await anyio.to_thread.run_sync(
functools.partial(func, *args, **kwargs),
@@ -53,10 +28,7 @@ async def to_thread(
def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]:
"""
Take a blocking function and create an async one that receives the same
- positional and keyword arguments. For python version 3.9 and above, it uses
- asyncio.to_thread to run the function in a separate thread. For python version
- 3.8, it uses locally defined copy of the asyncio.to_thread function which was
- introduced in python 3.9.
+ positional and keyword arguments.
Usage:
diff --git a/src/brand/dev/_version.py b/src/brand/dev/_version.py
index 1730d0d..ab7552d 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.19.1" # x-release-please-version
+__version__ = "1.20.0" # x-release-please-version
diff --git a/src/brand/dev/resources/brand.py b/src/brand/dev/resources/brand.py
index 8749438..5574c02 100644
--- a/src/brand/dev/resources/brand.py
+++ b/src/brand/dev/resources/brand.py
@@ -14,6 +14,7 @@
brand_screenshot_params,
brand_styleguide_params,
brand_retrieve_naics_params,
+ brand_retrieve_by_isin_params,
brand_retrieve_by_name_params,
brand_retrieve_by_email_params,
brand_retrieve_by_ticker_params,
@@ -37,6 +38,7 @@
from ..types.brand_screenshot_response import BrandScreenshotResponse
from ..types.brand_styleguide_response import BrandStyleguideResponse
from ..types.brand_retrieve_naics_response import BrandRetrieveNaicsResponse
+from ..types.brand_retrieve_by_isin_response import BrandRetrieveByIsinResponse
from ..types.brand_retrieve_by_name_response import BrandRetrieveByNameResponse
from ..types.brand_retrieve_by_email_response import BrandRetrieveByEmailResponse
from ..types.brand_retrieve_by_ticker_response import BrandRetrieveByTickerResponse
@@ -515,6 +517,122 @@ def retrieve_by_email(
cast_to=BrandRetrieveByEmailResponse,
)
+ def retrieve_by_isin(
+ self,
+ *,
+ isin: str,
+ force_language: Literal[
+ "albanian",
+ "arabic",
+ "azeri",
+ "bengali",
+ "bulgarian",
+ "cebuano",
+ "croatian",
+ "czech",
+ "danish",
+ "dutch",
+ "english",
+ "estonian",
+ "farsi",
+ "finnish",
+ "french",
+ "german",
+ "hausa",
+ "hawaiian",
+ "hindi",
+ "hungarian",
+ "icelandic",
+ "indonesian",
+ "italian",
+ "kazakh",
+ "kyrgyz",
+ "latin",
+ "latvian",
+ "lithuanian",
+ "macedonian",
+ "mongolian",
+ "nepali",
+ "norwegian",
+ "pashto",
+ "pidgin",
+ "polish",
+ "portuguese",
+ "romanian",
+ "russian",
+ "serbian",
+ "slovak",
+ "slovene",
+ "somali",
+ "spanish",
+ "swahili",
+ "swedish",
+ "tagalog",
+ "turkish",
+ "ukrainian",
+ "urdu",
+ "uzbek",
+ "vietnamese",
+ "welsh",
+ ]
+ | Omit = omit,
+ max_speed: bool | Omit = omit,
+ 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,
+ ) -> BrandRetrieveByIsinResponse:
+ """
+ Retrieve brand information using an ISIN (International Securities
+ Identification Number). This endpoint looks up the company associated with the
+ ISIN and returns its brand data.
+
+ Args:
+ isin: ISIN (International Securities Identification Number) to retrieve brand data for
+ (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters
+ followed by 9 alphanumeric characters and ending with a digit.
+
+ force_language: Optional parameter to force the language of the retrieved brand data.
+
+ max_speed: Optional parameter to optimize the API call for maximum speed. When set to true,
+ the API will skip time-consuming operations for faster response at the cost of
+ less comprehensive data.
+
+ 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/retrieve-by-isin",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "isin": isin,
+ "force_language": force_language,
+ "max_speed": max_speed,
+ "timeout_ms": timeout_ms,
+ },
+ brand_retrieve_by_isin_params.BrandRetrieveByIsinParams,
+ ),
+ ),
+ cast_to=BrandRetrieveByIsinResponse,
+ )
+
def retrieve_by_name(
self,
*,
@@ -1517,6 +1635,122 @@ async def retrieve_by_email(
cast_to=BrandRetrieveByEmailResponse,
)
+ async def retrieve_by_isin(
+ self,
+ *,
+ isin: str,
+ force_language: Literal[
+ "albanian",
+ "arabic",
+ "azeri",
+ "bengali",
+ "bulgarian",
+ "cebuano",
+ "croatian",
+ "czech",
+ "danish",
+ "dutch",
+ "english",
+ "estonian",
+ "farsi",
+ "finnish",
+ "french",
+ "german",
+ "hausa",
+ "hawaiian",
+ "hindi",
+ "hungarian",
+ "icelandic",
+ "indonesian",
+ "italian",
+ "kazakh",
+ "kyrgyz",
+ "latin",
+ "latvian",
+ "lithuanian",
+ "macedonian",
+ "mongolian",
+ "nepali",
+ "norwegian",
+ "pashto",
+ "pidgin",
+ "polish",
+ "portuguese",
+ "romanian",
+ "russian",
+ "serbian",
+ "slovak",
+ "slovene",
+ "somali",
+ "spanish",
+ "swahili",
+ "swedish",
+ "tagalog",
+ "turkish",
+ "ukrainian",
+ "urdu",
+ "uzbek",
+ "vietnamese",
+ "welsh",
+ ]
+ | Omit = omit,
+ max_speed: bool | Omit = omit,
+ 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,
+ ) -> BrandRetrieveByIsinResponse:
+ """
+ Retrieve brand information using an ISIN (International Securities
+ Identification Number). This endpoint looks up the company associated with the
+ ISIN and returns its brand data.
+
+ Args:
+ isin: ISIN (International Securities Identification Number) to retrieve brand data for
+ (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters
+ followed by 9 alphanumeric characters and ending with a digit.
+
+ force_language: Optional parameter to force the language of the retrieved brand data.
+
+ max_speed: Optional parameter to optimize the API call for maximum speed. When set to true,
+ the API will skip time-consuming operations for faster response at the cost of
+ less comprehensive data.
+
+ 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/retrieve-by-isin",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "isin": isin,
+ "force_language": force_language,
+ "max_speed": max_speed,
+ "timeout_ms": timeout_ms,
+ },
+ brand_retrieve_by_isin_params.BrandRetrieveByIsinParams,
+ ),
+ ),
+ cast_to=BrandRetrieveByIsinResponse,
+ )
+
async def retrieve_by_name(
self,
*,
@@ -2069,6 +2303,9 @@ def __init__(self, brand: BrandResource) -> None:
self.retrieve_by_email = to_raw_response_wrapper(
brand.retrieve_by_email,
)
+ self.retrieve_by_isin = to_raw_response_wrapper(
+ brand.retrieve_by_isin,
+ )
self.retrieve_by_name = to_raw_response_wrapper(
brand.retrieve_by_name,
)
@@ -2108,6 +2345,9 @@ def __init__(self, brand: AsyncBrandResource) -> None:
self.retrieve_by_email = async_to_raw_response_wrapper(
brand.retrieve_by_email,
)
+ self.retrieve_by_isin = async_to_raw_response_wrapper(
+ brand.retrieve_by_isin,
+ )
self.retrieve_by_name = async_to_raw_response_wrapper(
brand.retrieve_by_name,
)
@@ -2147,6 +2387,9 @@ def __init__(self, brand: BrandResource) -> None:
self.retrieve_by_email = to_streamed_response_wrapper(
brand.retrieve_by_email,
)
+ self.retrieve_by_isin = to_streamed_response_wrapper(
+ brand.retrieve_by_isin,
+ )
self.retrieve_by_name = to_streamed_response_wrapper(
brand.retrieve_by_name,
)
@@ -2186,6 +2429,9 @@ def __init__(self, brand: AsyncBrandResource) -> None:
self.retrieve_by_email = async_to_streamed_response_wrapper(
brand.retrieve_by_email,
)
+ self.retrieve_by_isin = async_to_streamed_response_wrapper(
+ brand.retrieve_by_isin,
+ )
self.retrieve_by_name = async_to_streamed_response_wrapper(
brand.retrieve_by_name,
)
diff --git a/src/brand/dev/types/__init__.py b/src/brand/dev/types/__init__.py
index bd36eb4..eae55c9 100644
--- a/src/brand/dev/types/__init__.py
+++ b/src/brand/dev/types/__init__.py
@@ -13,9 +13,11 @@
from .brand_screenshot_response import BrandScreenshotResponse as BrandScreenshotResponse
from .brand_styleguide_response import BrandStyleguideResponse as BrandStyleguideResponse
from .brand_retrieve_naics_params import BrandRetrieveNaicsParams as BrandRetrieveNaicsParams
+from .brand_retrieve_by_isin_params import BrandRetrieveByIsinParams as BrandRetrieveByIsinParams
from .brand_retrieve_by_name_params import BrandRetrieveByNameParams as BrandRetrieveByNameParams
from .brand_retrieve_naics_response import BrandRetrieveNaicsResponse as BrandRetrieveNaicsResponse
from .brand_retrieve_by_email_params import BrandRetrieveByEmailParams as BrandRetrieveByEmailParams
+from .brand_retrieve_by_isin_response import BrandRetrieveByIsinResponse as BrandRetrieveByIsinResponse
from .brand_retrieve_by_name_response import BrandRetrieveByNameResponse as BrandRetrieveByNameResponse
from .brand_retrieve_by_ticker_params import BrandRetrieveByTickerParams as BrandRetrieveByTickerParams
from .brand_retrieve_by_email_response import BrandRetrieveByEmailResponse as BrandRetrieveByEmailResponse
diff --git a/src/brand/dev/types/brand_retrieve_by_isin_params.py b/src/brand/dev/types/brand_retrieve_by_isin_params.py
new file mode 100644
index 0000000..db2731b
--- /dev/null
+++ b/src/brand/dev/types/brand_retrieve_by_isin_params.py
@@ -0,0 +1,88 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["BrandRetrieveByIsinParams"]
+
+
+class BrandRetrieveByIsinParams(TypedDict, total=False):
+ isin: Required[str]
+ """
+ ISIN (International Securities Identification Number) to retrieve brand data for
+ (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters
+ followed by 9 alphanumeric characters and ending with a digit.
+ """
+
+ force_language: Literal[
+ "albanian",
+ "arabic",
+ "azeri",
+ "bengali",
+ "bulgarian",
+ "cebuano",
+ "croatian",
+ "czech",
+ "danish",
+ "dutch",
+ "english",
+ "estonian",
+ "farsi",
+ "finnish",
+ "french",
+ "german",
+ "hausa",
+ "hawaiian",
+ "hindi",
+ "hungarian",
+ "icelandic",
+ "indonesian",
+ "italian",
+ "kazakh",
+ "kyrgyz",
+ "latin",
+ "latvian",
+ "lithuanian",
+ "macedonian",
+ "mongolian",
+ "nepali",
+ "norwegian",
+ "pashto",
+ "pidgin",
+ "polish",
+ "portuguese",
+ "romanian",
+ "russian",
+ "serbian",
+ "slovak",
+ "slovene",
+ "somali",
+ "spanish",
+ "swahili",
+ "swedish",
+ "tagalog",
+ "turkish",
+ "ukrainian",
+ "urdu",
+ "uzbek",
+ "vietnamese",
+ "welsh",
+ ]
+ """Optional parameter to force the language of the retrieved brand data."""
+
+ max_speed: Annotated[bool, PropertyInfo(alias="maxSpeed")]
+ """Optional parameter to optimize the API call for maximum speed.
+
+ When set to true, the API will skip time-consuming operations for faster
+ response at the cost of less comprehensive data.
+ """
+
+ 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_retrieve_by_isin_response.py b/src/brand/dev/types/brand_retrieve_by_isin_response.py
new file mode 100644
index 0000000..a9bbe4d
--- /dev/null
+++ b/src/brand/dev/types/brand_retrieve_by_isin_response.py
@@ -0,0 +1,481 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = [
+ "BrandRetrieveByIsinResponse",
+ "Brand",
+ "BrandAddress",
+ "BrandBackdrop",
+ "BrandBackdropColor",
+ "BrandBackdropResolution",
+ "BrandColor",
+ "BrandIndustries",
+ "BrandIndustriesEic",
+ "BrandLinks",
+ "BrandLogo",
+ "BrandLogoColor",
+ "BrandLogoResolution",
+ "BrandSocial",
+ "BrandStock",
+]
+
+
+class BrandAddress(BaseModel):
+ city: Optional[str] = None
+ """City name"""
+
+ country: Optional[str] = None
+ """Country name"""
+
+ country_code: Optional[str] = None
+ """Country code"""
+
+ postal_code: Optional[str] = None
+ """Postal or ZIP code"""
+
+ state_code: Optional[str] = None
+ """State or province code"""
+
+ state_province: Optional[str] = None
+ """State or province name"""
+
+ street: Optional[str] = None
+ """Street address"""
+
+
+class BrandBackdropColor(BaseModel):
+ hex: Optional[str] = None
+ """Color in hexadecimal format"""
+
+ name: Optional[str] = None
+ """Name of the color"""
+
+
+class BrandBackdropResolution(BaseModel):
+ aspect_ratio: Optional[float] = None
+ """Aspect ratio of the image (width/height)"""
+
+ height: Optional[int] = None
+ """Height of the image in pixels"""
+
+ width: Optional[int] = None
+ """Width of the image in pixels"""
+
+
+class BrandBackdrop(BaseModel):
+ colors: Optional[List[BrandBackdropColor]] = None
+ """Array of colors in the backdrop image"""
+
+ resolution: Optional[BrandBackdropResolution] = None
+ """Resolution of the backdrop image"""
+
+ url: Optional[str] = None
+ """URL of the backdrop image"""
+
+
+class BrandColor(BaseModel):
+ hex: Optional[str] = None
+ """Color in hexadecimal format"""
+
+ name: Optional[str] = None
+ """Name of the color"""
+
+
+class BrandIndustriesEic(BaseModel):
+ industry: Literal[
+ "Aerospace & Defense",
+ "Technology",
+ "Finance",
+ "Healthcare",
+ "Retail & E-commerce",
+ "Entertainment",
+ "Education",
+ "Government & Nonprofit",
+ "Industrial & Energy",
+ "Automotive & Transportation",
+ "Lifestyle & Leisure",
+ "Luxury & Fashion",
+ "News & Media",
+ "Sports",
+ "Real Estate & PropTech",
+ "Legal & Compliance",
+ "Telecommunications",
+ "Agriculture & Food",
+ "Professional Services & Agencies",
+ "Chemicals & Materials",
+ "Logistics & Supply Chain",
+ "Hospitality & Tourism",
+ "Construction & Built Environment",
+ "Consumer Packaged Goods (CPG)",
+ ]
+ """Industry classification enum"""
+
+ subindustry: Literal[
+ "Defense Systems & Military Hardware",
+ "Aerospace Manufacturing",
+ "Avionics & Navigation Technology",
+ "Subsea & Naval Defense Systems",
+ "Space & Satellite Technology",
+ "Defense IT & Systems Integration",
+ "Software (B2B)",
+ "Software (B2C)",
+ "Cloud Infrastructure & DevOps",
+ "Cybersecurity",
+ "Artificial Intelligence & Machine Learning",
+ "Data Infrastructure & Analytics",
+ "Hardware & Semiconductors",
+ "Fintech Infrastructure",
+ "eCommerce & Marketplace Platforms",
+ "Developer Tools & APIs",
+ "Web3 & Blockchain",
+ "XR & Spatial Computing",
+ "Banking & Lending",
+ "Investment Management & WealthTech",
+ "Insurance & InsurTech",
+ "Payments & Money Movement",
+ "Accounting, Tax & Financial Planning Tools",
+ "Capital Markets & Trading Platforms",
+ "Financial Infrastructure & APIs",
+ "Credit Scoring & Risk Management",
+ "Cryptocurrency & Digital Assets",
+ "BNPL & Alternative Financing",
+ "Healthcare Providers & Services",
+ "Pharmaceuticals & Drug Development",
+ "Medical Devices & Diagnostics",
+ "Biotechnology & Genomics",
+ "Digital Health & Telemedicine",
+ "Health Insurance & Benefits Tech",
+ "Clinical Trials & Research Platforms",
+ "Mental Health & Wellness",
+ "Healthcare IT & EHR Systems",
+ "Consumer Health & Wellness Products",
+ "Online Marketplaces",
+ "Direct-to-Consumer (DTC) Brands",
+ "Retail Tech & Point-of-Sale Systems",
+ "Omnichannel & In-Store Retail",
+ "E-commerce Enablement & Infrastructure",
+ "Subscription & Membership Commerce",
+ "Social Commerce & Influencer Platforms",
+ "Fashion & Apparel Retail",
+ "Food, Beverage & Grocery E-commerce",
+ "Streaming Platforms (Video, Music, Audio)",
+ "Gaming & Interactive Entertainment",
+ "Creator Economy & Influencer Platforms",
+ "Advertising, Adtech & Media Buying",
+ "Film, TV & Production Studios",
+ "Events, Venues & Live Entertainment",
+ "Virtual Worlds & Metaverse Experiences",
+ "K-12 Education Platforms & Tools",
+ "Higher Education & University Tech",
+ "Online Learning & MOOCs",
+ "Test Prep & Certification",
+ "Corporate Training & Upskilling",
+ "Tutoring & Supplemental Learning",
+ "Education Management Systems (LMS/SIS)",
+ "Language Learning",
+ "Creator-Led & Cohort-Based Courses",
+ "Special Education & Accessibility Tools",
+ "Government Technology & Digital Services",
+ "Civic Engagement & Policy Platforms",
+ "International Development & Humanitarian Aid",
+ "Philanthropy & Grantmaking",
+ "Nonprofit Operations & Fundraising Tools",
+ "Public Health & Social Services",
+ "Education & Youth Development Programs",
+ "Environmental & Climate Action Organizations",
+ "Legal Aid & Social Justice Advocacy",
+ "Municipal & Infrastructure Services",
+ "Manufacturing & Industrial Automation",
+ "Energy Production (Oil, Gas, Nuclear)",
+ "Renewable Energy & Cleantech",
+ "Utilities & Grid Infrastructure",
+ "Industrial IoT & Monitoring Systems",
+ "Construction & Heavy Equipment",
+ "Mining & Natural Resources",
+ "Environmental Engineering & Sustainability",
+ "Energy Storage & Battery Technology",
+ "Automotive OEMs & Vehicle Manufacturing",
+ "Electric Vehicles (EVs) & Charging Infrastructure",
+ "Mobility-as-a-Service (MaaS)",
+ "Fleet Management",
+ "Public Transit & Urban Mobility",
+ "Autonomous Vehicles & ADAS",
+ "Aftermarket Parts & Services",
+ "Telematics & Vehicle Connectivity",
+ "Aviation & Aerospace Transport",
+ "Maritime Shipping",
+ "Fitness & Wellness",
+ "Beauty & Personal Care",
+ "Home & Living",
+ "Dating & Relationships",
+ "Hobbies, Crafts & DIY",
+ "Outdoor & Recreational Gear",
+ "Events, Experiences & Ticketing Platforms",
+ "Designer & Luxury Apparel",
+ "Accessories, Jewelry & Watches",
+ "Footwear & Leather Goods",
+ "Beauty, Fragrance & Skincare",
+ "Fashion Marketplaces & Retail Platforms",
+ "Sustainable & Ethical Fashion",
+ "Resale, Vintage & Circular Fashion",
+ "Fashion Tech & Virtual Try-Ons",
+ "Streetwear & Emerging Luxury",
+ "Couture & Made-to-Measure",
+ "News Publishing & Journalism",
+ "Digital Media & Content Platforms",
+ "Broadcasting (TV & Radio)",
+ "Podcasting & Audio Media",
+ "News Aggregators & Curation Tools",
+ "Independent & Creator-Led Media",
+ "Newsletters & Substack-Style Platforms",
+ "Political & Investigative Media",
+ "Trade & Niche Publications",
+ "Media Monitoring & Analytics",
+ "Professional Teams & Leagues",
+ "Sports Media & Broadcasting",
+ "Sports Betting & Fantasy Sports",
+ "Fitness & Athletic Training Platforms",
+ "Sportswear & Equipment",
+ "Esports & Competitive Gaming",
+ "Sports Venues & Event Management",
+ "Athlete Management & Talent Agencies",
+ "Sports Tech & Performance Analytics",
+ "Youth, Amateur & Collegiate Sports",
+ "Real Estate Marketplaces",
+ "Property Management Software",
+ "Rental Platforms",
+ "Mortgage & Lending Tech",
+ "Real Estate Investment Platforms",
+ "Law Firms & Legal Services",
+ "Legal Tech & Automation",
+ "Regulatory Compliance",
+ "E-Discovery & Litigation Tools",
+ "Contract Management",
+ "Governance, Risk & Compliance (GRC)",
+ "IP & Trademark Management",
+ "Legal Research & Intelligence",
+ "Compliance Training & Certification",
+ "Whistleblower & Ethics Reporting",
+ "Mobile & Wireless Networks (3G/4G/5G)",
+ "Broadband & Fiber Internet",
+ "Satellite & Space-Based Communications",
+ "Network Equipment & Infrastructure",
+ "Telecom Billing & OSS/BSS Systems",
+ "VoIP & Unified Communications",
+ "Internet Service Providers (ISPs)",
+ "Edge Computing & Network Virtualization",
+ "IoT Connectivity Platforms",
+ "Precision Agriculture & AgTech",
+ "Crop & Livestock Production",
+ "Food & Beverage Manufacturing & Processing",
+ "Food Distribution",
+ "Restaurants & Food Service",
+ "Agricultural Inputs & Equipment",
+ "Sustainable & Regenerative Agriculture",
+ "Seafood & Aquaculture",
+ "Management Consulting",
+ "Marketing & Advertising Agencies",
+ "Design, Branding & Creative Studios",
+ "IT Services & Managed Services",
+ "Staffing, Recruiting & Talent",
+ "Accounting & Tax Firms",
+ "Public Relations & Communications",
+ "Business Process Outsourcing (BPO)",
+ "Professional Training & Coaching",
+ "Specialty Chemicals",
+ "Commodity & Petrochemicals",
+ "Polymers, Plastics & Rubber",
+ "Coatings, Adhesives & Sealants",
+ "Industrial Gases",
+ "Advanced Materials & Composites",
+ "Battery Materials & Energy Storage",
+ "Electronic Materials & Semiconductor Chemicals",
+ "Agrochemicals & Fertilizers",
+ "Freight & Transportation Tech",
+ "Last-Mile Delivery",
+ "Warehouse Automation",
+ "Supply Chain Visibility Platforms",
+ "Logistics Marketplaces",
+ "Shipping & Freight Forwarding",
+ "Cold Chain Logistics",
+ "Reverse Logistics & Returns",
+ "Cross-Border Trade Tech",
+ "Transportation Management Systems (TMS)",
+ "Hotels & Accommodation",
+ "Vacation Rentals & Short-Term Stays",
+ "Restaurant Tech & Management",
+ "Travel Booking Platforms",
+ "Tourism Experiences & Activities",
+ "Cruise Lines & Marine Tourism",
+ "Hospitality Management Systems",
+ "Event & Venue Management",
+ "Corporate Travel Management",
+ "Travel Insurance & Protection",
+ "Construction Management Software",
+ "BIM/CAD & Design Tools",
+ "Construction Marketplaces",
+ "Equipment Rental & Management",
+ "Building Materials & Procurement",
+ "Construction Workforce Management",
+ "Project Estimation & Bidding",
+ "Modular & Prefab Construction",
+ "Construction Safety & Compliance",
+ "Smart Building Technology",
+ "Food & Beverage CPG",
+ "Home & Personal Care CPG",
+ "CPG Analytics & Insights",
+ "Direct-to-Consumer CPG Brands",
+ "CPG Supply Chain & Distribution",
+ "Private Label Manufacturing",
+ "CPG Retail Intelligence",
+ "Sustainable CPG & Packaging",
+ "Beauty & Cosmetics CPG",
+ "Health & Wellness CPG",
+ ]
+ """Subindustry classification enum"""
+
+
+class BrandIndustries(BaseModel):
+ eic: Optional[List[BrandIndustriesEic]] = None
+ """Easy Industry Classification - array of industry and subindustry pairs"""
+
+
+class BrandLinks(BaseModel):
+ blog: Optional[str] = None
+ """URL to the brand's blog or news page"""
+
+ careers: Optional[str] = None
+ """URL to the brand's careers or job opportunities page"""
+
+ contact: Optional[str] = None
+ """URL to the brand's contact or contact us page"""
+
+ pricing: Optional[str] = None
+ """URL to the brand's pricing or plans page"""
+
+ privacy: Optional[str] = None
+ """URL to the brand's privacy policy page"""
+
+ terms: Optional[str] = None
+ """URL to the brand's terms of service or terms and conditions page"""
+
+
+class BrandLogoColor(BaseModel):
+ hex: Optional[str] = None
+ """Color in hexadecimal format"""
+
+ name: Optional[str] = None
+ """Name of the color"""
+
+
+class BrandLogoResolution(BaseModel):
+ aspect_ratio: Optional[float] = None
+ """Aspect ratio of the image (width/height)"""
+
+ height: Optional[int] = None
+ """Height of the image in pixels"""
+
+ width: Optional[int] = None
+ """Width of the image in pixels"""
+
+
+class BrandLogo(BaseModel):
+ colors: Optional[List[BrandLogoColor]] = None
+ """Array of colors in the logo"""
+
+ mode: Optional[Literal["light", "dark", "has_opaque_background"]] = None
+ """
+ Indicates when this logo is best used: 'light' = best for light mode, 'dark' =
+ best for dark mode, 'has_opaque_background' = can be used for either as image
+ has its own background
+ """
+
+ resolution: Optional[BrandLogoResolution] = None
+ """Resolution of the logo image"""
+
+ type: Optional[Literal["icon", "logo"]] = None
+ """Type of the logo based on resolution (e.g., 'icon', 'logo')"""
+
+ url: Optional[str] = None
+ """CDN hosted url of the logo (ready for display)"""
+
+
+class BrandSocial(BaseModel):
+ type: Optional[str] = None
+ """Type of social media, e.g., 'facebook', 'twitter'"""
+
+ url: Optional[str] = None
+ """URL of the social media page"""
+
+
+class BrandStock(BaseModel):
+ exchange: Optional[str] = None
+ """Stock exchange name"""
+
+ ticker: Optional[str] = None
+ """Stock ticker symbol"""
+
+
+class Brand(BaseModel):
+ address: Optional[BrandAddress] = None
+ """Physical address of the brand"""
+
+ backdrops: Optional[List[BrandBackdrop]] = None
+ """An array of backdrop images for the brand"""
+
+ colors: Optional[List[BrandColor]] = None
+ """An array of brand colors"""
+
+ description: Optional[str] = None
+ """A brief description of the brand"""
+
+ domain: Optional[str] = None
+ """The domain name of the brand"""
+
+ email: Optional[str] = None
+ """Company email address"""
+
+ industries: Optional[BrandIndustries] = None
+ """Industry classification information for the brand"""
+
+ is_nsfw: Optional[bool] = None
+ """Indicates whether the brand content is not safe for work (NSFW)"""
+
+ links: Optional[BrandLinks] = None
+ """Important website links for the brand"""
+
+ logos: Optional[List[BrandLogo]] = None
+ """An array of logos associated with the brand"""
+
+ phone: Optional[str] = None
+ """Company phone number"""
+
+ slogan: Optional[str] = None
+ """The brand's slogan"""
+
+ socials: Optional[List[BrandSocial]] = None
+ """An array of social media links for the brand"""
+
+ stock: Optional[BrandStock] = None
+ """
+ Stock market information for this brand (will be null if not a publicly traded
+ company)
+ """
+
+ title: Optional[str] = None
+ """The title or name of the brand"""
+
+
+class BrandRetrieveByIsinResponse(BaseModel):
+ brand: Optional[Brand] = None
+ """Detailed brand information"""
+
+ code: Optional[int] = None
+ """HTTP status code"""
+
+ status: Optional[str] = None
+ """Status of the response, e.g., 'ok'"""
diff --git a/tests/api_resources/test_brand.py b/tests/api_resources/test_brand.py
index 7dfc647..2963c49 100644
--- a/tests/api_resources/test_brand.py
+++ b/tests/api_resources/test_brand.py
@@ -16,6 +16,7 @@
BrandScreenshotResponse,
BrandStyleguideResponse,
BrandRetrieveNaicsResponse,
+ BrandRetrieveByIsinResponse,
BrandRetrieveByNameResponse,
BrandRetrieveByEmailResponse,
BrandRetrieveByTickerResponse,
@@ -286,6 +287,51 @@ def test_streaming_response_retrieve_by_email(self, client: BrandDev) -> None:
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_retrieve_by_isin(self, client: BrandDev) -> None:
+ brand = client.brand.retrieve_by_isin(
+ isin="SE60513A9993",
+ )
+ assert_matches_type(BrandRetrieveByIsinResponse, brand, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_retrieve_by_isin_with_all_params(self, client: BrandDev) -> None:
+ brand = client.brand.retrieve_by_isin(
+ isin="SE60513A9993",
+ force_language="albanian",
+ max_speed=True,
+ timeout_ms=1,
+ )
+ assert_matches_type(BrandRetrieveByIsinResponse, brand, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve_by_isin(self, client: BrandDev) -> None:
+ response = client.brand.with_raw_response.retrieve_by_isin(
+ isin="SE60513A9993",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ brand = response.parse()
+ assert_matches_type(BrandRetrieveByIsinResponse, brand, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve_by_isin(self, client: BrandDev) -> None:
+ with client.brand.with_streaming_response.retrieve_by_isin(
+ isin="SE60513A9993",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ brand = response.parse()
+ assert_matches_type(BrandRetrieveByIsinResponse, brand, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_retrieve_by_name(self, client: BrandDev) -> None:
@@ -815,6 +861,51 @@ async def test_streaming_response_retrieve_by_email(self, async_client: AsyncBra
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_retrieve_by_isin(self, async_client: AsyncBrandDev) -> None:
+ brand = await async_client.brand.retrieve_by_isin(
+ isin="SE60513A9993",
+ )
+ assert_matches_type(BrandRetrieveByIsinResponse, brand, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_retrieve_by_isin_with_all_params(self, async_client: AsyncBrandDev) -> None:
+ brand = await async_client.brand.retrieve_by_isin(
+ isin="SE60513A9993",
+ force_language="albanian",
+ max_speed=True,
+ timeout_ms=1,
+ )
+ assert_matches_type(BrandRetrieveByIsinResponse, brand, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_retrieve_by_isin(self, async_client: AsyncBrandDev) -> None:
+ response = await async_client.brand.with_raw_response.retrieve_by_isin(
+ isin="SE60513A9993",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ brand = await response.parse()
+ assert_matches_type(BrandRetrieveByIsinResponse, brand, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_retrieve_by_isin(self, async_client: AsyncBrandDev) -> None:
+ async with async_client.brand.with_streaming_response.retrieve_by_isin(
+ isin="SE60513A9993",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ brand = await response.parse()
+ assert_matches_type(BrandRetrieveByIsinResponse, brand, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_retrieve_by_name(self, async_client: AsyncBrandDev) -> None:
diff --git a/tests/test_models.py b/tests/test_models.py
index 44e5d4c..66e3565 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -9,7 +9,7 @@
from brand.dev._utils import PropertyInfo
from brand.dev._compat import PYDANTIC_V1, parse_obj, model_dump, model_json
-from brand.dev._models import BaseModel, construct_type
+from brand.dev._models import DISCRIMINATOR_CACHE, BaseModel, construct_type
class BasicModel(BaseModel):
@@ -809,7 +809,7 @@ class B(BaseModel):
UnionType = cast(Any, Union[A, B])
- assert not hasattr(UnionType, "__discriminator__")
+ assert not DISCRIMINATOR_CACHE.get(UnionType)
m = construct_type(
value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")])
@@ -818,7 +818,7 @@ class B(BaseModel):
assert m.type == "b"
assert m.data == "foo" # type: ignore[comparison-overlap]
- discriminator = UnionType.__discriminator__
+ discriminator = DISCRIMINATOR_CACHE.get(UnionType)
assert discriminator is not None
m = construct_type(
@@ -830,7 +830,7 @@ class B(BaseModel):
# if the discriminator details object stays the same between invocations then
# we hit the cache
- assert UnionType.__discriminator__ is discriminator
+ assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator
@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1")