diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b286e5a..81f6dc20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,6 @@ jobs: lint: name: lint runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 @@ -33,7 +32,6 @@ jobs: test: name: test runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 10f30916..b06ba919 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.2.0" + ".": "0.2.1" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index bf9e8e0e..79ca4185 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 32 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/mixedbread%2Fmixedbread-82c2c1c322149cd73b2e8e45f475919b941752a89e74464ccecd1aee9352e9be.yml openapi_spec_hash: a47fe4cb39ee0cb74ee5888de2f0a5e1 -config_hash: 6d1076e161e84bae54e1b0df1015d37e +config_hash: 6a7c1faa96b022a6959d720d7957eade diff --git a/CHANGELOG.md b/CHANGELOG.md index 908548a1..8d4abbb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 0.2.1 (2025-04-12) + +Full Changelog: [v0.2.0...v0.2.1](https://github.com/mixedbread-ai/mixedbread-python/compare/v0.2.0...v0.2.1) + +### Bug Fixes + +* **perf:** skip traversing types for NotGiven values ([77ca84f](https://github.com/mixedbread-ai/mixedbread-python/commit/77ca84fd479fdc4bb8e097ce77717fb7d6351974)) + + +### Chores + +* **internal:** expand CI branch coverage ([a3c7c80](https://github.com/mixedbread-ai/mixedbread-python/commit/a3c7c80a2e913a3f53e95eb7c85637f9fbaed2b2)) +* **internal:** reduce CI branch coverage ([bf50b05](https://github.com/mixedbread-ai/mixedbread-python/commit/bf50b0586e3b716afe2e09ff19b0ddf6eb835db1)) +* **internal:** slight transform perf improvement ([#196](https://github.com/mixedbread-ai/mixedbread-python/issues/196)) ([65548f9](https://github.com/mixedbread-ai/mixedbread-python/commit/65548f934aae308b4ae4f44158d789c74436501a)) +* slight wording improvement in README ([#198](https://github.com/mixedbread-ai/mixedbread-python/issues/198)) ([5bbfa5a](https://github.com/mixedbread-ai/mixedbread-python/commit/5bbfa5acac3c1d9fd6c476f7e1ebf44ee317cacb)) +* **tests:** improve enum examples ([#197](https://github.com/mixedbread-ai/mixedbread-python/issues/197)) ([662d9f5](https://github.com/mixedbread-ai/mixedbread-python/commit/662d9f5cfdb106d43b9d55fc85bc5b2ea78af7c4)) + ## 0.2.0 (2025-04-08) Full Changelog: [v0.1.0...v0.2.0](https://github.com/mixedbread-ai/mixedbread-python/compare/v0.1.0...v0.2.0) diff --git a/README.md b/README.md index 0c9b9688..831cfdec 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ print(vector_store.expires_after) ## File uploads -Request parameters that correspond to file uploads can be passed as `bytes`, a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. +Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. ```python from pathlib import Path diff --git a/pyproject.toml b/pyproject.toml index cfb02939..61c45f44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mixedbread" -version = "0.2.0" +version = "0.2.1" description = "The official Python library for the Mixedbread API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/mixedbread/_utils/_transform.py b/src/mixedbread/_utils/_transform.py index 7ac2e17f..3b2b8e00 100644 --- a/src/mixedbread/_utils/_transform.py +++ b/src/mixedbread/_utils/_transform.py @@ -12,6 +12,7 @@ from ._utils import ( is_list, + is_given, is_mapping, is_iterable, ) @@ -142,6 +143,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 +189,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): @@ -245,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 @@ -332,6 +351,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): @@ -393,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/src/mixedbread/_version.py b/src/mixedbread/_version.py index 593e3c09..2c97ccc1 100644 --- a/src/mixedbread/_version.py +++ b/src/mixedbread/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "mixedbread" -__version__ = "0.2.0" # x-release-please-version +__version__ = "0.2.1" # x-release-please-version diff --git a/tests/api_resources/test_vector_stores.py b/tests/api_resources/test_vector_stores.py index bc9e0ab3..5a367783 100644 --- a/tests/api_resources/test_vector_stores.py +++ b/tests/api_resources/test_vector_stores.py @@ -240,7 +240,7 @@ def test_method_question_answering_with_all_params(self, client: Mixedbread) -> { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -252,7 +252,7 @@ def test_method_question_answering_with_all_params(self, client: Mixedbread) -> { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -264,7 +264,7 @@ def test_method_question_answering_with_all_params(self, client: Mixedbread) -> { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -328,7 +328,7 @@ def test_method_search_with_all_params(self, client: Mixedbread) -> None: { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -340,7 +340,7 @@ def test_method_search_with_all_params(self, client: Mixedbread) -> None: { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -352,7 +352,7 @@ def test_method_search_with_all_params(self, client: Mixedbread) -> None: { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -617,7 +617,7 @@ async def test_method_question_answering_with_all_params(self, async_client: Asy { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -629,7 +629,7 @@ async def test_method_question_answering_with_all_params(self, async_client: Asy { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -641,7 +641,7 @@ async def test_method_question_answering_with_all_params(self, async_client: Asy { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -705,7 +705,7 @@ async def test_method_search_with_all_params(self, async_client: AsyncMixedbread { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -717,7 +717,7 @@ async def test_method_search_with_all_params(self, async_client: AsyncMixedbread { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -729,7 +729,7 @@ async def test_method_search_with_all_params(self, async_client: AsyncMixedbread { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", diff --git a/tests/api_resources/vector_stores/test_files.py b/tests/api_resources/vector_stores/test_files.py index ff4d7a91..e089a591 100644 --- a/tests/api_resources/vector_stores/test_files.py +++ b/tests/api_resources/vector_stores/test_files.py @@ -239,7 +239,7 @@ def test_method_search_with_all_params(self, client: Mixedbread) -> None: { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -251,7 +251,7 @@ def test_method_search_with_all_params(self, client: Mixedbread) -> None: { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -263,7 +263,7 @@ def test_method_search_with_all_params(self, client: Mixedbread) -> None: { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -529,7 +529,7 @@ async def test_method_search_with_all_params(self, async_client: AsyncMixedbread { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -541,7 +541,7 @@ async def test_method_search_with_all_params(self, async_client: AsyncMixedbread { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", @@ -553,7 +553,7 @@ async def test_method_search_with_all_params(self, async_client: AsyncMixedbread { "key": "price", "value": "100", - "operator": "eq", + "operator": "gt", }, { "key": "color", diff --git a/tests/test_transform.py b/tests/test_transform.py index 4cedd6a2..d3c69d8e 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -8,7 +8,7 @@ import pytest -from mixedbread._types import Base64FileInput +from mixedbread._types import NOT_GIVEN, Base64FileInput from mixedbread._utils import ( PropertyInfo, transform as _transform, @@ -432,3 +432,22 @@ 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] + + +@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) == {}