From 3c5cd0a60b3d33248568075ccb3576536d5cfe7e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 02:32:26 +0000 Subject: [PATCH 1/8] chore(internal): slight transform perf improvement (#448) --- src/openlayer/_utils/_transform.py | 22 ++++++++++++++++++++++ tests/test_transform.py | 12 ++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/openlayer/_utils/_transform.py b/src/openlayer/_utils/_transform.py index 7ac2e17f..3ec62081 100644 --- a/src/openlayer/_utils/_transform.py +++ b/src/openlayer/_utils/_transform.py @@ -142,6 +142,10 @@ def _maybe_transform_key(key: str, type_: type) -> str: return key +def _no_transform_needed(annotation: type) -> bool: + return annotation == float or annotation == int + + def _transform_recursive( data: object, *, @@ -184,6 +188,15 @@ def _transform_recursive( return cast(object, data) inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] if is_union_type(stripped_type): @@ -332,6 +345,15 @@ async def _async_transform_recursive( return cast(object, data) inner_type = extract_type_arg(stripped_type, 0) + if _no_transform_needed(inner_type): + # for some types there is no need to transform anything, so we can get a small + # perf boost from skipping that work. + # + # but we still need to convert to a list to ensure the data is json-serializable + if is_list(data): + return data + return list(data) + return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] if is_union_type(stripped_type): diff --git a/tests/test_transform.py b/tests/test_transform.py index 043b1020..ffc9f827 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -432,3 +432,15 @@ async def test_base64_file_input(use_async: bool) -> None: assert await transform({"foo": io.BytesIO(b"Hello, world!")}, TypedDictBase64Input, use_async) == { "foo": "SGVsbG8sIHdvcmxkIQ==" } # type: ignore[comparison-overlap] + + +@parametrize +@pytest.mark.asyncio +async def test_transform_skipping(use_async: bool) -> None: + # lists of ints are left as-is + data = [1, 2, 3] + assert await transform(data, List[int], use_async) is data + + # iterables of ints are converted to a list + data = iter([1, 2, 3]) + assert await transform(data, Iterable[int], use_async) == [1, 2, 3] From 350872865c9f574048c4d6acb112ee72f81e5046 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 02:33:05 +0000 Subject: [PATCH 2/8] chore(tests): improve enum examples (#449) --- tests/api_resources/commits/test_test_results.py | 4 ++-- tests/api_resources/inference_pipelines/test_test_results.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/api_resources/commits/test_test_results.py b/tests/api_resources/commits/test_test_results.py index da776599..83853215 100644 --- a/tests/api_resources/commits/test_test_results.py +++ b/tests/api_resources/commits/test_test_results.py @@ -31,7 +31,7 @@ def test_method_list_with_all_params(self, client: Openlayer) -> None: include_archived=True, page=1, per_page=1, - status="running", + status="passing", type="integrity", ) assert_matches_type(TestResultListResponse, test_result, path=["response"]) @@ -85,7 +85,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenlayer) - include_archived=True, page=1, per_page=1, - status="running", + status="passing", type="integrity", ) assert_matches_type(TestResultListResponse, test_result, path=["response"]) diff --git a/tests/api_resources/inference_pipelines/test_test_results.py b/tests/api_resources/inference_pipelines/test_test_results.py index 2d5bc065..210aa423 100644 --- a/tests/api_resources/inference_pipelines/test_test_results.py +++ b/tests/api_resources/inference_pipelines/test_test_results.py @@ -30,7 +30,7 @@ def test_method_list_with_all_params(self, client: Openlayer) -> None: inference_pipeline_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", page=1, per_page=1, - status="running", + status="passing", type="integrity", ) assert_matches_type(TestResultListResponse, test_result, path=["response"]) @@ -83,7 +83,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenlayer) - inference_pipeline_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", page=1, per_page=1, - status="running", + status="passing", type="integrity", ) assert_matches_type(TestResultListResponse, test_result, path=["response"]) From 121cc4cf1e7276aba8fde9ca216db17242b641ed Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 02:49:31 +0000 Subject: [PATCH 3/8] chore(internal): expand CI branch coverage --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ac5f63f..b8920208 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,18 @@ name: CI on: push: - branches: - - main - pull_request: - branches: - - main - - next + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'preview-head/**' + - 'preview-base/**' + - 'preview/**' jobs: lint: name: lint runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 From 05f20c8ff1b471a9a3f3d6f688d0cc7d78cf680b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 02:54:06 +0000 Subject: [PATCH 4/8] chore(internal): reduce CI branch coverage --- .github/workflows/ci.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8920208..e8b72361 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,13 +1,12 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'preview-head/**' - - 'preview-base/**' - - 'preview/**' + branches: + - main + pull_request: + branches: + - main + - next jobs: lint: From afb01083b15f4b4f4878176f2d34a74c72ef3c57 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 12 Apr 2025 02:47:53 +0000 Subject: [PATCH 5/8] fix(perf): skip traversing types for NotGiven values --- src/openlayer/_utils/_transform.py | 11 +++++++++++ tests/test_transform.py | 9 ++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/openlayer/_utils/_transform.py b/src/openlayer/_utils/_transform.py index 3ec62081..3b2b8e00 100644 --- a/src/openlayer/_utils/_transform.py +++ b/src/openlayer/_utils/_transform.py @@ -12,6 +12,7 @@ from ._utils import ( is_list, + is_given, is_mapping, is_iterable, ) @@ -258,6 +259,11 @@ def _transform_typeddict( result: dict[str, object] = {} annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): + if not is_given(value): + # we don't need to include `NotGiven` values here as they'll + # be stripped out before the request is sent anyway + continue + type_ = annotations.get(key) if type_ is None: # we do not have a type annotation for this field, leave it as is @@ -415,6 +421,11 @@ async def _async_transform_typeddict( result: dict[str, object] = {} annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): + if not is_given(value): + # we don't need to include `NotGiven` values here as they'll + # be stripped out before the request is sent anyway + continue + type_ = annotations.get(key) if type_ is None: # we do not have a type annotation for this field, leave it as is diff --git a/tests/test_transform.py b/tests/test_transform.py index ffc9f827..8c5ab27a 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -8,7 +8,7 @@ import pytest -from openlayer._types import Base64FileInput +from openlayer._types import NOT_GIVEN, Base64FileInput from openlayer._utils import ( PropertyInfo, transform as _transform, @@ -444,3 +444,10 @@ async def test_transform_skipping(use_async: bool) -> None: # iterables of ints are converted to a list data = iter([1, 2, 3]) assert await transform(data, Iterable[int], use_async) == [1, 2, 3] + + +@parametrize +@pytest.mark.asyncio +async def test_strips_notgiven(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": NOT_GIVEN}, Foo1, use_async) == {} From badc2bb1b915c70045a4f9150792746788a61b79 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 12 Apr 2025 02:49:06 +0000 Subject: [PATCH 6/8] fix(perf): optimize some hot paths --- src/openlayer/_utils/_transform.py | 14 +++++++++++++- src/openlayer/_utils/_typing.py | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/openlayer/_utils/_transform.py b/src/openlayer/_utils/_transform.py index 3b2b8e00..b0cc20a7 100644 --- a/src/openlayer/_utils/_transform.py +++ b/src/openlayer/_utils/_transform.py @@ -5,7 +5,7 @@ import pathlib from typing import Any, Mapping, TypeVar, cast from datetime import date, datetime -from typing_extensions import Literal, get_args, override, get_type_hints +from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints import anyio import pydantic @@ -13,6 +13,7 @@ from ._utils import ( is_list, is_given, + lru_cache, is_mapping, is_iterable, ) @@ -109,6 +110,7 @@ class Params(TypedDict, total=False): return cast(_T, transformed) +@lru_cache(maxsize=8096) def _get_annotated_type(type_: type) -> type | None: """If the given type is an `Annotated` type then it is returned, if not `None` is returned. @@ -433,3 +435,13 @@ async def _async_transform_typeddict( else: result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) return result + + +@lru_cache(maxsize=8096) +def get_type_hints( + obj: Any, + globalns: dict[str, Any] | None = None, + localns: Mapping[str, Any] | None = None, + include_extras: bool = False, +) -> dict[str, Any]: + return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/src/openlayer/_utils/_typing.py b/src/openlayer/_utils/_typing.py index 278749b1..1958820f 100644 --- a/src/openlayer/_utils/_typing.py +++ b/src/openlayer/_utils/_typing.py @@ -13,6 +13,7 @@ get_origin, ) +from ._utils import lru_cache from .._types import InheritsGeneric from .._compat import is_union as _is_union @@ -66,6 +67,7 @@ def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: # Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] +@lru_cache(maxsize=8096) def strip_annotated_type(typ: type) -> type: if is_required_type(typ) or is_annotated_type(typ): return strip_annotated_type(cast(type, get_args(typ)[0])) From 24dbdef53ccb988e6cd807094ae2a15a4e40fa7f Mon Sep 17 00:00:00 2001 From: Rishab Ramanathan Date: Mon, 14 Apr 2025 21:21:28 +0000 Subject: [PATCH 7/8] feat: feat: allow publish without ssl verification --- src/openlayer/lib/tracing/tracer.py | 41 +++++++++++++++++++---------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/openlayer/lib/tracing/tracer.py b/src/openlayer/lib/tracing/tracer.py index 4057ad0d..4e099416 100644 --- a/src/openlayer/lib/tracing/tracer.py +++ b/src/openlayer/lib/tracing/tracer.py @@ -1,25 +1,36 @@ """Module with the logic to create and manage traces and steps.""" +import time import asyncio -import contextvars import inspect import logging -import time -from contextlib import contextmanager +import contextvars +from typing import Any, Dict, List, Tuple, Optional, Awaitable, Generator from functools import wraps -from typing import Any, Awaitable, Dict, Generator, List, Optional, Tuple +from contextlib import contextmanager +from . import enums, steps, traces +from .. import utils from ..._client import Openlayer +from ..._base_client import DefaultHttpxClient from ...types.inference_pipelines.data_stream_params import ConfigLlmData -from .. import utils -from . import enums, steps, traces logger = logging.getLogger(__name__) -_publish = utils.get_env_variable("OPENLAYER_DISABLE_PUBLISH") != "true" +TRUE_LIST = ["true", "on", "1"] + +_publish = utils.get_env_variable("OPENLAYER_DISABLE_PUBLISH") not in TRUE_LIST +_verify_ssl = utils.get_env_variable("OPENLAYER_VERIFY_SSL").lower() in TRUE_LIST _client = None if _publish: - _client = Openlayer() + if _verify_ssl: + _client = Openlayer() + else: + _client = Openlayer( + http_client=DefaultHttpxClient( + verify=False, + ), + ) _current_step = contextvars.ContextVar("current_step") _current_trace = contextvars.ContextVar("current_trace") @@ -142,8 +153,8 @@ def trace( Examples -------- - To trace a function, simply decorate it with the ``@trace()`` decorator. By doing so, - the functions inputs, outputs, and metadata will be automatically logged to your + To trace a function, simply decorate it with the ``@trace()`` decorator. By doing + so, the functions inputs, outputs, and metadata will be automatically logged to your Openlayer project. >>> import os @@ -204,7 +215,8 @@ def wrapper(*func_args, **func_kwargs): log_context(inputs.get(context_kwarg)) else: logger.warning( - "Context kwarg `%s` not found in inputs of the current function.", + "Context kwarg `%s` not found in inputs of the " + "current function.", context_kwarg, ) @@ -235,8 +247,8 @@ def trace_async( Examples -------- - To trace a function, simply decorate it with the ``@trace()`` decorator. By doing so, - the functions inputs, outputs, and metadata will be automatically logged to your + To trace a function, simply decorate it with the ``@trace()`` decorator. By doing + so, the functions inputs, outputs, and metadata will be automatically logged to your Openlayer project. >>> import os @@ -297,7 +309,8 @@ async def wrapper(*func_args, **func_kwargs): log_context(inputs.get(context_kwarg)) else: logger.warning( - "Context kwarg `%s` not found in inputs of the current function.", + "Context kwarg `%s` not found in inputs of the " + "current function.", context_kwarg, ) From a47616b9d5b061d96b0244a23f43d09c012f9d12 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 21:21:46 +0000 Subject: [PATCH 8/8] release: 0.2.0-alpha.52 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 22 ++++++++++++++++++++++ pyproject.toml | 2 +- src/openlayer/_version.py | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 344687e1..da3cbca0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.2.0-alpha.51" + ".": "0.2.0-alpha.52" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index af69569e..9a6e30e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.2.0-alpha.52 (2025-04-14) + +Full Changelog: [v0.2.0-alpha.51...v0.2.0-alpha.52](https://github.com/openlayer-ai/openlayer-python/compare/v0.2.0-alpha.51...v0.2.0-alpha.52) + +### Features + +* feat: allow publish without ssl verification ([24dbdef](https://github.com/openlayer-ai/openlayer-python/commit/24dbdef53ccb988e6cd807094ae2a15a4e40fa7f)) + + +### Bug Fixes + +* **perf:** optimize some hot paths ([badc2bb](https://github.com/openlayer-ai/openlayer-python/commit/badc2bb1b915c70045a4f9150792746788a61b79)) +* **perf:** skip traversing types for NotGiven values ([afb0108](https://github.com/openlayer-ai/openlayer-python/commit/afb01083b15f4b4f4878176f2d34a74c72ef3c57)) + + +### Chores + +* **internal:** expand CI branch coverage ([121cc4c](https://github.com/openlayer-ai/openlayer-python/commit/121cc4cf1e7276aba8fde9ca216db17242b641ed)) +* **internal:** reduce CI branch coverage ([05f20c8](https://github.com/openlayer-ai/openlayer-python/commit/05f20c8ff1b471a9a3f3d6f688d0cc7d78cf680b)) +* **internal:** slight transform perf improvement ([#448](https://github.com/openlayer-ai/openlayer-python/issues/448)) ([3c5cd0a](https://github.com/openlayer-ai/openlayer-python/commit/3c5cd0a60b3d33248568075ccb3576536d5cfe7e)) +* **tests:** improve enum examples ([#449](https://github.com/openlayer-ai/openlayer-python/issues/449)) ([3508728](https://github.com/openlayer-ai/openlayer-python/commit/350872865c9f574048c4d6acb112ee72f81e5046)) + ## 0.2.0-alpha.51 (2025-04-04) Full Changelog: [v0.2.0-alpha.50...v0.2.0-alpha.51](https://github.com/openlayer-ai/openlayer-python/compare/v0.2.0-alpha.50...v0.2.0-alpha.51) diff --git a/pyproject.toml b/pyproject.toml index 16ba12c0..81f9b604 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openlayer" -version = "0.2.0-alpha.51" +version = "0.2.0-alpha.52" description = "The official Python library for the openlayer API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openlayer/_version.py b/src/openlayer/_version.py index 73709ebe..96631d01 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.51" # x-release-please-version +__version__ = "0.2.0-alpha.52" # x-release-please-version