From 1a0bc2372f93272e8907790b1dcda2f196f16970 Mon Sep 17 00:00:00 2001 From: stainless-bot Date: Thu, 20 Jun 2024 04:38:36 +0000 Subject: [PATCH] chore(internal): version bump --- .release-please-manifest.json | 2 +- pyproject.toml | 2 +- src/openlayer/_base_client.py | 25 ++++++++++++++++++++----- src/openlayer/_utils/__init__.py | 1 + src/openlayer/_utils/_reflection.py | 8 ++++++++ src/openlayer/_utils/_sync.py | 19 ++++++++++++++++++- src/openlayer/_version.py | 2 +- 7 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 src/openlayer/_utils/_reflection.py diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 43883fb2..08197a61 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.2.0-alpha.2" + ".": "0.2.0-alpha.3" } \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index f6f8db6d..f4daf3f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openlayer" -version = "0.2.0-alpha.2" +version = "0.2.0-alpha.3" description = "The official Python library for the openlayer API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openlayer/_base_client.py b/src/openlayer/_base_client.py index e56f38d8..c8de9db7 100644 --- a/src/openlayer/_base_client.py +++ b/src/openlayer/_base_client.py @@ -60,7 +60,7 @@ RequestOptions, ModelBuilderProtocol, ) -from ._utils import is_dict, is_list, is_given, lru_cache, is_mapping +from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping from ._compat import model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type from ._response import ( @@ -358,6 +358,7 @@ def __init__( self._custom_query = custom_query or {} self._strict_response_validation = _strict_response_validation self._idempotency_header = None + self._platform: Platform | None = None if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] raise TypeError( @@ -456,7 +457,7 @@ def _build_request( raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") headers = self._build_headers(options) - params = _merge_mappings(self._custom_query, options.params) + params = _merge_mappings(self.default_query, options.params) content_type = headers.get("Content-Type") # If the given Content-Type header is multipart/form-data then it @@ -592,6 +593,12 @@ def default_headers(self) -> dict[str, str | Omit]: **self._custom_headers, } + @property + def default_query(self) -> dict[str, object]: + return { + **self._custom_query, + } + def _validate_headers( self, headers: Headers, # noqa: ARG002 @@ -616,7 +623,10 @@ def base_url(self, url: URL | str) -> None: self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url)) def platform_headers(self) -> Dict[str, str]: - return platform_headers(self._version) + # the actual implementation is in a separate `lru_cache` decorated + # function because adding `lru_cache` to methods will leak memory + # https://github.com/python/cpython/issues/88476 + return platform_headers(self._version, platform=self._platform) def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None: """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified. @@ -1492,6 +1502,11 @@ async def _request( stream_cls: type[_AsyncStreamT] | None, remaining_retries: int | None, ) -> ResponseT | _AsyncStreamT: + if self._platform is None: + # `get_platform` can make blocking IO calls so we + # execute it earlier while we are in an async context + self._platform = await asyncify(get_platform)() + cast_to = self._maybe_override_cast_to(cast_to, options) await self._prepare_options(options) @@ -1915,11 +1930,11 @@ def get_platform() -> Platform: @lru_cache(maxsize=None) -def platform_headers(version: str) -> Dict[str, str]: +def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]: return { "X-Stainless-Lang": "python", "X-Stainless-Package-Version": version, - "X-Stainless-OS": str(get_platform()), + "X-Stainless-OS": str(platform or get_platform()), "X-Stainless-Arch": str(get_architecture()), "X-Stainless-Runtime": get_python_runtime(), "X-Stainless-Runtime-Version": get_python_version(), diff --git a/src/openlayer/_utils/__init__.py b/src/openlayer/_utils/__init__.py index 31b5b227..667e2473 100644 --- a/src/openlayer/_utils/__init__.py +++ b/src/openlayer/_utils/__init__.py @@ -49,3 +49,4 @@ maybe_transform as maybe_transform, async_maybe_transform as async_maybe_transform, ) +from ._reflection import function_has_argument as function_has_argument diff --git a/src/openlayer/_utils/_reflection.py b/src/openlayer/_utils/_reflection.py new file mode 100644 index 00000000..e134f58e --- /dev/null +++ b/src/openlayer/_utils/_reflection.py @@ -0,0 +1,8 @@ +import inspect +from typing import Any, Callable + + +def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: + """Returns whether or not the given function has a specific parameter""" + sig = inspect.signature(func) + return arg_name in sig.parameters diff --git a/src/openlayer/_utils/_sync.py b/src/openlayer/_utils/_sync.py index 595924e5..d0d81033 100644 --- a/src/openlayer/_utils/_sync.py +++ b/src/openlayer/_utils/_sync.py @@ -7,6 +7,8 @@ import anyio import anyio.to_thread +from ._reflection import function_has_argument + T_Retval = TypeVar("T_Retval") T_ParamSpec = ParamSpec("T_ParamSpec") @@ -59,6 +61,21 @@ def do_work(arg1, arg2, kwarg1="", kwarg2="") -> str: async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: partial_f = functools.partial(function, *args, **kwargs) - return await anyio.to_thread.run_sync(partial_f, cancellable=cancellable, limiter=limiter) + + # In `v4.1.0` anyio added the `abandon_on_cancel` argument and deprecated the old + # `cancellable` argument, so we need to use the new `abandon_on_cancel` to avoid + # surfacing deprecation warnings. + if function_has_argument(anyio.to_thread.run_sync, "abandon_on_cancel"): + return await anyio.to_thread.run_sync( + partial_f, + abandon_on_cancel=cancellable, + limiter=limiter, + ) + + return await anyio.to_thread.run_sync( + partial_f, + cancellable=cancellable, + limiter=limiter, + ) return wrapper diff --git a/src/openlayer/_version.py b/src/openlayer/_version.py index a4bf32af..7124b0d1 100644 --- a/src/openlayer/_version.py +++ b/src/openlayer/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "openlayer" -__version__ = "0.2.0-alpha.2" # x-release-please-version +__version__ = "0.2.0-alpha.3" # x-release-please-version