Skip to content

Commit fb7ec43

Browse files
release: 1.1.0 (#96)
* chore(internal): change default timeout to an int (#95) * chore(internal): bummp ruff dependency (#97) * feat(client): send `X-Stainless-Read-Timeout` header (#98) * chore(internal): fix type traversing dictionary params (#99) * chore(internal): minor type handling changes (#100) * release: 1.1.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent b1da195 commit fb7ec43

File tree

11 files changed

+62
-14
lines changed

11 files changed

+62
-14
lines changed

.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.0.1"
2+
".": "1.1.0"
33
}

CHANGELOG.md

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

3+
## 1.1.0 (2025-02-07)
4+
5+
Full Changelog: [v1.0.1...v1.1.0](https://github.com/ArcadeAI/arcade-py/compare/v1.0.1...v1.1.0)
6+
7+
### Features
8+
9+
* **client:** send `X-Stainless-Read-Timeout` header ([#98](https://github.com/ArcadeAI/arcade-py/issues/98)) ([ed2a2f9](https://github.com/ArcadeAI/arcade-py/commit/ed2a2f91ed9b0d0f97bf70ad63006b59ff0a7e96))
10+
11+
12+
### Chores
13+
14+
* **internal:** bummp ruff dependency ([#97](https://github.com/ArcadeAI/arcade-py/issues/97)) ([354784c](https://github.com/ArcadeAI/arcade-py/commit/354784ce85e1327bfde56746da97cc2016690a61))
15+
* **internal:** change default timeout to an int ([#95](https://github.com/ArcadeAI/arcade-py/issues/95)) ([bcac267](https://github.com/ArcadeAI/arcade-py/commit/bcac26785cf90888478adb3455b2e667d442c135))
16+
* **internal:** fix type traversing dictionary params ([#99](https://github.com/ArcadeAI/arcade-py/issues/99)) ([8d4ccf0](https://github.com/ArcadeAI/arcade-py/commit/8d4ccf0f26850f9cbb2e76c0126712f8a87567f8))
17+
* **internal:** minor type handling changes ([#100](https://github.com/ArcadeAI/arcade-py/issues/100)) ([3adf96e](https://github.com/ArcadeAI/arcade-py/commit/3adf96e565dcf2c62ed0490fb92833a09dd2a1f8))
18+
319
## 1.0.1 (2025-01-25)
420

521
Full Changelog: [v1.0.0...v1.0.1](https://github.com/ArcadeAI/arcade-py/compare/v1.0.0...v1.0.1)

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "arcadepy"
3-
version = "1.0.1"
3+
version = "1.1.0"
44
description = "The official Python library for the Arcade API"
55
dynamic = ["readme"]
66
license = "MIT"
@@ -177,7 +177,7 @@ select = [
177177
"T201",
178178
"T203",
179179
# misuse of typing.TYPE_CHECKING
180-
"TCH004",
180+
"TC004",
181181
# import rules
182182
"TID251",
183183
]

requirements-dev.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pytz==2023.3.post1
7878
# via dirty-equals
7979
respx==0.22.0
8080
rich==13.7.1
81-
ruff==0.6.9
81+
ruff==0.9.4
8282
setuptools==68.2.2
8383
# via nodeenv
8484
six==1.16.0

scripts/utils/ruffen-docs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def _md_match(match: Match[str]) -> str:
4747
with _collect_error(match):
4848
code = format_code_block(code)
4949
code = textwrap.indent(code, match["indent"])
50-
return f'{match["before"]}{code}{match["after"]}'
50+
return f"{match['before']}{code}{match['after']}"
5151

5252
def _pycon_match(match: Match[str]) -> str:
5353
code = ""
@@ -97,7 +97,7 @@ def finish_fragment() -> None:
9797
def _md_pycon_match(match: Match[str]) -> str:
9898
code = _pycon_match(match)
9999
code = textwrap.indent(code, match["indent"])
100-
return f'{match["before"]}{code}{match["after"]}'
100+
return f"{match['before']}{code}{match['after']}"
101101

102102
src = MD_RE.sub(_md_match, src)
103103
src = MD_PYCON_RE.sub(_md_pycon_match, src)

src/arcadepy/_base_client.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,10 +418,17 @@ def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0
418418
if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers:
419419
headers[idempotency_header] = options.idempotency_key or self._idempotency_key()
420420

421-
# Don't set the retry count header if it was already set or removed by the caller. We check
421+
# Don't set these headers if they were already set or removed by the caller. We check
422422
# `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case.
423-
if "x-stainless-retry-count" not in (header.lower() for header in custom_headers):
423+
lower_custom_headers = [header.lower() for header in custom_headers]
424+
if "x-stainless-retry-count" not in lower_custom_headers:
424425
headers["x-stainless-retry-count"] = str(retries_taken)
426+
if "x-stainless-read-timeout" not in lower_custom_headers:
427+
timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout
428+
if isinstance(timeout, Timeout):
429+
timeout = timeout.read
430+
if timeout is not None:
431+
headers["x-stainless-read-timeout"] = str(timeout)
425432

426433
return headers
427434

src/arcadepy/_constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to"
77

88
# default timeout is 1 minute
9-
DEFAULT_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0)
9+
DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0)
1010
DEFAULT_MAX_RETRIES = 2
1111
DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20)
1212

src/arcadepy/_models.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ def to_json(
172172
@override
173173
def __str__(self) -> str:
174174
# mypy complains about an invalid self arg
175-
return f'{self.__repr_name__()}({self.__repr_str__(", ")})' # type: ignore[misc]
175+
return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc]
176176

177177
# Override the 'construct' method in a way that supports recursive parsing without validation.
178178
# Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836.
@@ -426,10 +426,16 @@ def construct_type(*, value: object, type_: object) -> object:
426426
427427
If the given value does not match the expected type then it is returned as-is.
428428
"""
429+
430+
# store a reference to the original type we were given before we extract any inner
431+
# types so that we can properly resolve forward references in `TypeAliasType` annotations
432+
original_type = None
433+
429434
# we allow `object` as the input type because otherwise, passing things like
430435
# `Literal['value']` will be reported as a type error by type checkers
431436
type_ = cast("type[object]", type_)
432437
if is_type_alias_type(type_):
438+
original_type = type_ # type: ignore[unreachable]
433439
type_ = type_.__value__ # type: ignore[unreachable]
434440

435441
# unwrap `Annotated[T, ...]` -> `T`
@@ -446,7 +452,7 @@ def construct_type(*, value: object, type_: object) -> object:
446452

447453
if is_union(origin):
448454
try:
449-
return validate_type(type_=cast("type[object]", type_), value=value)
455+
return validate_type(type_=cast("type[object]", original_type or type_), value=value)
450456
except Exception:
451457
pass
452458

src/arcadepy/_utils/_transform.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
is_annotated_type,
2626
strip_annotated_type,
2727
)
28-
from .._compat import model_dump, is_typeddict
28+
from .._compat import get_origin, model_dump, is_typeddict
2929

3030
_T = TypeVar("_T")
3131

@@ -164,9 +164,14 @@ def _transform_recursive(
164164
inner_type = annotation
165165

166166
stripped_type = strip_annotated_type(inner_type)
167+
origin = get_origin(stripped_type) or stripped_type
167168
if is_typeddict(stripped_type) and is_mapping(data):
168169
return _transform_typeddict(data, stripped_type)
169170

171+
if origin == dict and is_mapping(data):
172+
items_type = get_args(stripped_type)[1]
173+
return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()}
174+
170175
if (
171176
# List[T]
172177
(is_list_type(stripped_type) and is_list(data))
@@ -307,9 +312,14 @@ async def _async_transform_recursive(
307312
inner_type = annotation
308313

309314
stripped_type = strip_annotated_type(inner_type)
315+
origin = get_origin(stripped_type) or stripped_type
310316
if is_typeddict(stripped_type) and is_mapping(data):
311317
return await _async_transform_typeddict(data, stripped_type)
312318

319+
if origin == dict and is_mapping(data):
320+
items_type = get_args(stripped_type)[1]
321+
return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()}
322+
313323
if (
314324
# List[T]
315325
(is_list_type(stripped_type) and is_list(data))

src/arcadepy/_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__ = "arcadepy"
4-
__version__ = "1.0.1" # x-release-please-version
4+
__version__ = "1.1.0" # x-release-please-version

0 commit comments

Comments
 (0)