Skip to content

Commit a8efd59

Browse files
authored
Merge pull request #26 from brand-dot-dev/release-please--branches--main--changes--next
release: 1.20.0
2 parents 0903f71 + c19334f commit a8efd59

15 files changed

Lines changed: 984 additions & 62 deletions

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "1.19.1"
2+
".": "1.20.0"
33
}

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 11
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-6620330945de41f1c453692af40842f08fe1fd281ff6ba4e79d447c941ebd783.yml
3-
openapi_spec_hash: 861a43669d27d942d4bd3e36a398e95b
4-
config_hash: 083e432ea397a9018371145493400188
1+
configured_endpoints: 12
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-070cac50467cd07e8601e948fc97e3c82ea0630d6a0b0f24164335e396893e6a.yml
3+
openapi_spec_hash: b887bcfe688f72b3a34ee24246d12955
4+
config_hash: 86160e220c81f47769a71c9343e486d8

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Changelog
22

3+
## 1.20.0 (2025-11-19)
4+
5+
Full Changelog: [v1.19.1...v1.20.0](https://github.com/brand-dot-dev/python-sdk/compare/v1.19.1...v1.20.0)
6+
7+
### Features
8+
9+
* **api:** manual updates ([152e848](https://github.com/brand-dot-dev/python-sdk/commit/152e8489b6ecbbe717d48ac0c437e88c64e923a5))
10+
11+
12+
### Bug Fixes
13+
14+
* compat with Python 3.14 ([8602245](https://github.com/brand-dot-dev/python-sdk/commit/860224506b4fe79750cff976b1bed305f4f826da))
15+
* **compat:** update signatures of `model_dump` and `model_dump_json` for Pydantic v1 ([768e2d1](https://github.com/brand-dot-dev/python-sdk/commit/768e2d13ddf92adde07ad4715419caa4b3257338))
16+
17+
18+
### Chores
19+
20+
* **package:** drop Python 3.8 support ([ecc46d0](https://github.com/brand-dot-dev/python-sdk/commit/ecc46d081a6d8ecbbdb633e444218f0d12487f2b))
21+
322
## 1.19.1 (2025-11-04)
423

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

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<!-- prettier-ignore -->
44
[![PyPI version](https://img.shields.io/pypi/v/brand.dev.svg?label=pypi%20(stable))](https://pypi.org/project/brand.dev/)
55

6-
The Brand Dev Python library provides convenient access to the Brand Dev REST API from any Python 3.8+
6+
The Brand Dev Python library provides convenient access to the Brand Dev REST API from any Python 3.9+
77
application. The library includes type definitions for all request params and response fields,
88
and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).
99

@@ -396,7 +396,7 @@ print(brand.dev.__version__)
396396

397397
## Requirements
398398

399-
Python 3.8 or higher.
399+
Python 3.9 or higher.
400400

401401
## Contributing
402402

api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ from brand.dev.types import (
99
BrandIdentifyFromTransactionResponse,
1010
BrandPrefetchResponse,
1111
BrandRetrieveByEmailResponse,
12+
BrandRetrieveByIsinResponse,
1213
BrandRetrieveByNameResponse,
1314
BrandRetrieveByTickerResponse,
1415
BrandRetrieveNaicsResponse,
@@ -25,6 +26,7 @@ Methods:
2526
- <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>
2627
- <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>
2728
- <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>
29+
- <code title="get /brand/retrieve-by-isin">client.brand.<a href="./src/brand/dev/resources/brand.py">retrieve_by_isin</a>(\*\*<a href="src/brand/dev/types/brand_retrieve_by_isin_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_retrieve_by_isin_response.py">BrandRetrieveByIsinResponse</a></code>
2830
- <code title="get /brand/retrieve-by-name">client.brand.<a href="./src/brand/dev/resources/brand.py">retrieve_by_name</a>(\*\*<a href="src/brand/dev/types/brand_retrieve_by_name_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_retrieve_by_name_response.py">BrandRetrieveByNameResponse</a></code>
2931
- <code title="get /brand/retrieve-by-ticker">client.brand.<a href="./src/brand/dev/resources/brand.py">retrieve_by_ticker</a>(\*\*<a href="src/brand/dev/types/brand_retrieve_by_ticker_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_retrieve_by_ticker_response.py">BrandRetrieveByTickerResponse</a></code>
3032
- <code title="get /brand/naics">client.brand.<a href="./src/brand/dev/resources/brand.py">retrieve_naics</a>(\*\*<a href="src/brand/dev/types/brand_retrieve_naics_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_retrieve_naics_response.py">BrandRetrieveNaicsResponse</a></code>

pyproject.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "brand.dev"
3-
version = "1.19.1"
3+
version = "1.20.0"
44
description = "The official Python library for the brand.dev API"
55
dynamic = ["readme"]
66
license = "Apache-2.0"
@@ -15,11 +15,10 @@ dependencies = [
1515
"distro>=1.7.0, <2",
1616
"sniffio",
1717
]
18-
requires-python = ">= 3.8"
18+
requires-python = ">= 3.9"
1919
classifiers = [
2020
"Typing :: Typed",
2121
"Intended Audience :: Developers",
22-
"Programming Language :: Python :: 3.8",
2322
"Programming Language :: Python :: 3.9",
2423
"Programming Language :: Python :: 3.10",
2524
"Programming Language :: Python :: 3.11",
@@ -141,7 +140,7 @@ filterwarnings = [
141140
# there are a couple of flags that are still disabled by
142141
# default in strict mode as they are experimental and niche.
143142
typeCheckingMode = "strict"
144-
pythonVersion = "3.8"
143+
pythonVersion = "3.9"
145144

146145
exclude = [
147146
"_dev",

src/brand/dev/_models.py

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
import inspect
5+
import weakref
56
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
67
from datetime import date, datetime
78
from typing_extensions import (
@@ -256,32 +257,41 @@ def model_dump(
256257
mode: Literal["json", "python"] | str = "python",
257258
include: IncEx | None = None,
258259
exclude: IncEx | None = None,
260+
context: Any | None = None,
259261
by_alias: bool | None = None,
260262
exclude_unset: bool = False,
261263
exclude_defaults: bool = False,
262264
exclude_none: bool = False,
265+
exclude_computed_fields: bool = False,
263266
round_trip: bool = False,
264267
warnings: bool | Literal["none", "warn", "error"] = True,
265-
context: dict[str, Any] | None = None,
266-
serialize_as_any: bool = False,
267268
fallback: Callable[[Any], Any] | None = None,
269+
serialize_as_any: bool = False,
268270
) -> dict[str, Any]:
269271
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump
270272
271273
Generate a dictionary representation of the model, optionally specifying which fields to include or exclude.
272274
273275
Args:
274276
mode: The mode in which `to_python` should run.
275-
If mode is 'json', the dictionary will only contain JSON serializable types.
276-
If mode is 'python', the dictionary may contain any Python objects.
277-
include: A list of fields to include in the output.
278-
exclude: A list of fields to exclude from the output.
277+
If mode is 'json', the output will only contain JSON serializable types.
278+
If mode is 'python', the output may contain non-JSON-serializable Python objects.
279+
include: A set of fields to include in the output.
280+
exclude: A set of fields to exclude from the output.
281+
context: Additional context to pass to the serializer.
279282
by_alias: Whether to use the field's alias in the dictionary key if defined.
280-
exclude_unset: Whether to exclude fields that are unset or None from the output.
281-
exclude_defaults: Whether to exclude fields that are set to their default value from the output.
282-
exclude_none: Whether to exclude fields that have a value of `None` from the output.
283-
round_trip: Whether to enable serialization and deserialization round-trip support.
284-
warnings: Whether to log warnings when invalid fields are encountered.
283+
exclude_unset: Whether to exclude fields that have not been explicitly set.
284+
exclude_defaults: Whether to exclude fields that are set to their default value.
285+
exclude_none: Whether to exclude fields that have a value of `None`.
286+
exclude_computed_fields: Whether to exclude computed fields.
287+
While this can be useful for round-tripping, it is usually recommended to use the dedicated
288+
`round_trip` parameter instead.
289+
round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T].
290+
warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors,
291+
"error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError].
292+
fallback: A function to call when an unknown value is encountered. If not provided,
293+
a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised.
294+
serialize_as_any: Whether to serialize fields with duck-typing serialization behavior.
285295
286296
Returns:
287297
A dictionary representation of the model.
@@ -298,6 +308,8 @@ def model_dump(
298308
raise ValueError("serialize_as_any is only supported in Pydantic v2")
299309
if fallback is not None:
300310
raise ValueError("fallback is only supported in Pydantic v2")
311+
if exclude_computed_fields != False:
312+
raise ValueError("exclude_computed_fields is only supported in Pydantic v2")
301313
dumped = super().dict( # pyright: ignore[reportDeprecated]
302314
include=include,
303315
exclude=exclude,
@@ -314,15 +326,17 @@ def model_dump_json(
314326
self,
315327
*,
316328
indent: int | None = None,
329+
ensure_ascii: bool = False,
317330
include: IncEx | None = None,
318331
exclude: IncEx | None = None,
332+
context: Any | None = None,
319333
by_alias: bool | None = None,
320334
exclude_unset: bool = False,
321335
exclude_defaults: bool = False,
322336
exclude_none: bool = False,
337+
exclude_computed_fields: bool = False,
323338
round_trip: bool = False,
324339
warnings: bool | Literal["none", "warn", "error"] = True,
325-
context: dict[str, Any] | None = None,
326340
fallback: Callable[[Any], Any] | None = None,
327341
serialize_as_any: bool = False,
328342
) -> str:
@@ -354,6 +368,10 @@ def model_dump_json(
354368
raise ValueError("serialize_as_any is only supported in Pydantic v2")
355369
if fallback is not None:
356370
raise ValueError("fallback is only supported in Pydantic v2")
371+
if ensure_ascii != False:
372+
raise ValueError("ensure_ascii is only supported in Pydantic v2")
373+
if exclude_computed_fields != False:
374+
raise ValueError("exclude_computed_fields is only supported in Pydantic v2")
357375
return super().json( # type: ignore[reportDeprecated]
358376
indent=indent,
359377
include=include,
@@ -573,6 +591,9 @@ class CachedDiscriminatorType(Protocol):
573591
__discriminator__: DiscriminatorDetails
574592

575593

594+
DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary()
595+
596+
576597
class DiscriminatorDetails:
577598
field_name: str
578599
"""The name of the discriminator field in the variant class, e.g.
@@ -615,8 +636,9 @@ def __init__(
615636

616637

617638
def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None:
618-
if isinstance(union, CachedDiscriminatorType):
619-
return union.__discriminator__
639+
cached = DISCRIMINATOR_CACHE.get(union)
640+
if cached is not None:
641+
return cached
620642

621643
discriminator_field_name: str | None = None
622644

@@ -669,7 +691,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any,
669691
discriminator_field=discriminator_field_name,
670692
discriminator_alias=discriminator_alias,
671693
)
672-
cast(CachedDiscriminatorType, union).__discriminator__ = details
694+
DISCRIMINATOR_CACHE.setdefault(union, details)
673695
return details
674696

675697

src/brand/dev/_utils/_sync.py

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
from __future__ import annotations
22

3-
import sys
43
import asyncio
54
import functools
6-
import contextvars
7-
from typing import Any, TypeVar, Callable, Awaitable
5+
from typing import TypeVar, Callable, Awaitable
86
from typing_extensions import ParamSpec
97

108
import anyio
@@ -15,34 +13,11 @@
1513
T_ParamSpec = ParamSpec("T_ParamSpec")
1614

1715

18-
if sys.version_info >= (3, 9):
19-
_asyncio_to_thread = asyncio.to_thread
20-
else:
21-
# backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
22-
# for Python 3.8 support
23-
async def _asyncio_to_thread(
24-
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
25-
) -> Any:
26-
"""Asynchronously run function *func* in a separate thread.
27-
28-
Any *args and **kwargs supplied for this function are directly passed
29-
to *func*. Also, the current :class:`contextvars.Context` is propagated,
30-
allowing context variables from the main thread to be accessed in the
31-
separate thread.
32-
33-
Returns a coroutine that can be awaited to get the eventual result of *func*.
34-
"""
35-
loop = asyncio.events.get_running_loop()
36-
ctx = contextvars.copy_context()
37-
func_call = functools.partial(ctx.run, func, *args, **kwargs)
38-
return await loop.run_in_executor(None, func_call)
39-
40-
4116
async def to_thread(
4217
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
4318
) -> T_Retval:
4419
if sniffio.current_async_library() == "asyncio":
45-
return await _asyncio_to_thread(func, *args, **kwargs)
20+
return await asyncio.to_thread(func, *args, **kwargs)
4621

4722
return await anyio.to_thread.run_sync(
4823
functools.partial(func, *args, **kwargs),
@@ -53,10 +28,7 @@ async def to_thread(
5328
def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]:
5429
"""
5530
Take a blocking function and create an async one that receives the same
56-
positional and keyword arguments. For python version 3.9 and above, it uses
57-
asyncio.to_thread to run the function in a separate thread. For python version
58-
3.8, it uses locally defined copy of the asyncio.to_thread function which was
59-
introduced in python 3.9.
31+
positional and keyword arguments.
6032
6133
Usage:
6234

src/brand/dev/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "brand.dev"
4-
__version__ = "1.19.1" # x-release-please-version
4+
__version__ = "1.20.0" # x-release-please-version

0 commit comments

Comments
 (0)