Skip to content

Commit 8327e60

Browse files
Certifi update (#56)
1 parent c210117 commit 8327e60

24 files changed

+82
-44
lines changed

aimon/_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

aimon/_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

aimon/_files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def assert_is_file_content(obj: object, *, key: str | None = None) -> None:
3434
if not is_file_content(obj):
3535
prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`"
3636
raise RuntimeError(
37-
f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead."
37+
f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead. See https://github.com/stainless-sdks/aimonlabs-python/tree/main#file-uploads"
3838
) from None
3939

4040

aimon/_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

aimon/_response.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
136136
if cast_to and is_annotated_type(cast_to):
137137
cast_to = extract_type_arg(cast_to, 0)
138138

139+
origin = get_origin(cast_to) or cast_to
140+
139141
if self._is_sse_stream:
140142
if to:
141143
if not is_stream_class_type(to):
@@ -195,8 +197,6 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
195197
if cast_to == bool:
196198
return cast(R, response.text.lower() == "true")
197199

198-
origin = get_origin(cast_to) or cast_to
199-
200200
if origin == APIResponse:
201201
raise RuntimeError("Unexpected state - cast_to is `APIResponse`")
202202

aimon/_utils/_sync.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77
from typing import Any, TypeVar, Callable, Awaitable
88
from typing_extensions import ParamSpec
99

10+
import anyio
11+
import sniffio
12+
import anyio.to_thread
13+
1014
T_Retval = TypeVar("T_Retval")
1115
T_ParamSpec = ParamSpec("T_ParamSpec")
1216

1317

1418
if sys.version_info >= (3, 9):
15-
to_thread = asyncio.to_thread
19+
_asyncio_to_thread = asyncio.to_thread
1620
else:
1721
# backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
1822
# for Python 3.8 support
19-
async def to_thread(
23+
async def _asyncio_to_thread(
2024
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
2125
) -> Any:
2226
"""Asynchronously run function *func* in a separate thread.
@@ -34,6 +38,17 @@ async def to_thread(
3438
return await loop.run_in_executor(None, func_call)
3539

3640

41+
async def to_thread(
42+
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
43+
) -> T_Retval:
44+
if sniffio.current_async_library() == "asyncio":
45+
return await _asyncio_to_thread(func, *args, **kwargs)
46+
47+
return await anyio.to_thread.run_sync(
48+
functools.partial(func, *args, **kwargs),
49+
)
50+
51+
3752
# inspired by `asyncer`, https://github.com/tiangolo/asyncer
3853
def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]:
3954
"""

aimon/_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))

aimon/_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__ = "aimon"
4-
__version__ = "0.9.0"
4+
__version__ = "0.9.1"

aimon/resources/analyze.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class AnalyzeResource(SyncAPIResource):
3030
@cached_property
3131
def with_raw_response(self) -> AnalyzeResourceWithRawResponse:
3232
"""
33-
This property can be used as a prefix for any HTTP method call to return the
33+
This property can be used as a prefix for any HTTP method call to return
3434
the raw response object instead of the parsed content.
3535
3636
For more information, see https://github.com/stainless-sdks/aimonlabs-python#accessing-raw-response-data-eg-headers
@@ -83,7 +83,7 @@ class AsyncAnalyzeResource(AsyncAPIResource):
8383
@cached_property
8484
def with_raw_response(self) -> AsyncAnalyzeResourceWithRawResponse:
8585
"""
86-
This property can be used as a prefix for any HTTP method call to return the
86+
This property can be used as a prefix for any HTTP method call to return
8787
the raw response object instead of the parsed content.
8888
8989
For more information, see https://github.com/stainless-sdks/aimonlabs-python#accessing-raw-response-data-eg-headers

aimon/resources/applications/applications.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def production(self) -> ProductionResource:
5757
@cached_property
5858
def with_raw_response(self) -> ApplicationsResourceWithRawResponse:
5959
"""
60-
This property can be used as a prefix for any HTTP method call to return the
60+
This property can be used as a prefix for any HTTP method call to return
6161
the raw response object instead of the parsed content.
6262
6363
For more information, see https://github.com/stainless-sdks/aimonlabs-python#accessing-raw-response-data-eg-headers
@@ -239,7 +239,7 @@ def production(self) -> AsyncProductionResource:
239239
@cached_property
240240
def with_raw_response(self) -> AsyncApplicationsResourceWithRawResponse:
241241
"""
242-
This property can be used as a prefix for any HTTP method call to return the
242+
This property can be used as a prefix for any HTTP method call to return
243243
the raw response object instead of the parsed content.
244244
245245
For more information, see https://github.com/stainless-sdks/aimonlabs-python#accessing-raw-response-data-eg-headers

0 commit comments

Comments
 (0)