diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b286e5ae..81f6dc20f 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 ee93e8ac5..b69919dfd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.221.0" + ".": "0.222.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 31b1c0195..853824a8f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 199 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/increase%2Fincrease-b21d5da00193c0adcbbc6bb89b6eba07c1b8720b9c383e2496d9c68a9426925e.yml -openapi_spec_hash: fb8ac77c8609e18634121b86b378f332 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/increase%2Fincrease-f3fa36b4bd3a55445fc8f959c9023e2ace20ec8957e492288d45170f1f284ca6.yml +openapi_spec_hash: 837c92afcea095a3cdd40deca976839c config_hash: 20a463ecd33bd32b7b9bc6f4990907ac diff --git a/CHANGELOG.md b/CHANGELOG.md index d574be9ea..6bd63e729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 0.222.0 (2025-04-11) + +Full Changelog: [v0.221.0...v0.222.0](https://github.com/Increase/increase-python/compare/v0.221.0...v0.222.0) + +### Features + +* **api:** api update ([882f23a](https://github.com/Increase/increase-python/commit/882f23a04c5e1ffcd70ad8e0606ff239d6f8e4e3)) +* **api:** api update ([37aea5f](https://github.com/Increase/increase-python/commit/37aea5f7013dc8ab8d62af04f2b7242ff865ee6b)) + + +### Bug Fixes + +* **perf:** optimize some hot paths ([47997d9](https://github.com/Increase/increase-python/commit/47997d9c45f371f53d270ec5b1e2259b4463af9d)) +* **perf:** skip traversing types for NotGiven values ([b49443b](https://github.com/Increase/increase-python/commit/b49443b68419103351123fb86ec38abf3de3d7b2)) + + +### Chores + +* **internal:** expand CI branch coverage ([#1084](https://github.com/Increase/increase-python/issues/1084)) ([871f3bc](https://github.com/Increase/increase-python/commit/871f3bc1ff3e534707be922b49f1b6c8045cfa30)) +* **internal:** reduce CI branch coverage ([a32531a](https://github.com/Increase/increase-python/commit/a32531a5579b47fe22960e93b8107904a2c84139)) + ## 0.221.0 (2025-04-08) Full Changelog: [v0.220.0...v0.221.0](https://github.com/Increase/increase-python/compare/v0.220.0...v0.221.0) diff --git a/pyproject.toml b/pyproject.toml index 3c6d7f17f..bfbd23ae2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "increase" -version = "0.221.0" +version = "0.222.0" description = "The official Python library for the increase API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/increase/_utils/_transform.py b/src/increase/_utils/_transform.py index 3ec620818..b0cc20a73 100644 --- a/src/increase/_utils/_transform.py +++ b/src/increase/_utils/_transform.py @@ -5,13 +5,15 @@ 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 from ._utils import ( is_list, + is_given, + lru_cache, is_mapping, is_iterable, ) @@ -108,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. @@ -258,6 +261,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 +423,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 @@ -422,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/increase/_utils/_typing.py b/src/increase/_utils/_typing.py index 278749b14..1958820f8 100644 --- a/src/increase/_utils/_typing.py +++ b/src/increase/_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])) diff --git a/src/increase/_version.py b/src/increase/_version.py index 3f6444f3e..c6578183e 100644 --- a/src/increase/_version.py +++ b/src/increase/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "increase" -__version__ = "0.221.0" # x-release-please-version +__version__ = "0.222.0" # x-release-please-version diff --git a/src/increase/types/card_payment.py b/src/increase/types/card_payment.py index dbb24d19e..ccd604870 100644 --- a/src/increase/types/card_payment.py +++ b/src/increase/types/card_payment.py @@ -1280,10 +1280,11 @@ class ElementCardRefundCashback(BaseModel): class ElementCardRefundInterchange(BaseModel): amount: str - """The interchange amount given as a string containing a decimal number. - - The amount is a positive number if it is credited to Increase (e.g., - settlements) and a negative number if it is debited (e.g., refunds). + """ + The interchange amount given as a string containing a decimal number in major + units (so e.g., "3.14" for $3.14). The amount is a positive number if it is + credited to Increase (e.g., settlements) and a negative number if it is debited + (e.g., refunds). """ code: Optional[str] = None @@ -1961,10 +1962,11 @@ class ElementCardSettlementCashback(BaseModel): class ElementCardSettlementInterchange(BaseModel): amount: str - """The interchange amount given as a string containing a decimal number. - - The amount is a positive number if it is credited to Increase (e.g., - settlements) and a negative number if it is debited (e.g., refunds). + """ + The interchange amount given as a string containing a decimal number in major + units (so e.g., "3.14" for $3.14). The amount is a positive number if it is + credited to Increase (e.g., settlements) and a negative number if it is debited + (e.g., refunds). """ code: Optional[str] = None diff --git a/src/increase/types/check_transfer_create_params.py b/src/increase/types/check_transfer_create_params.py index a87148450..cc7d86ee8 100644 --- a/src/increase/types/check_transfer_create_params.py +++ b/src/increase/types/check_transfer_create_params.py @@ -100,6 +100,14 @@ class PhysicalCheck(TypedDict, total=False): recipient_name: Required[str] """The name that will be printed on the check in the 'To:' field.""" + attachment_file_id: str + """The ID of a File to be attached to the check. + + This must have `purpose: check_attachment`. For details on pricing and + restrictions, see + https://increase.com/documentation/originating-checks#printing-checks . + """ + check_number: str """The check number Increase should print on the check. @@ -118,6 +126,16 @@ class PhysicalCheck(TypedDict, total=False): as delivery failed and shred them. """ + shipping_method: Literal["usps_first_class", "fedex_overnight"] + """How to ship the check. + + For details on pricing, timing, and restrictions, see + https://increase.com/documentation/originating-checks#printing-checks . + + - `usps_first_class` - USPS First Class + - `fedex_overnight` - FedEx Overnight + """ + signature_text: str """The text that will appear as the signature on the check in cursive font. diff --git a/src/increase/types/transaction.py b/src/increase/types/transaction.py index 1f765d93f..3f49a6d99 100644 --- a/src/increase/types/transaction.py +++ b/src/increase/types/transaction.py @@ -433,10 +433,11 @@ class SourceCardRefundCashback(BaseModel): class SourceCardRefundInterchange(BaseModel): amount: str - """The interchange amount given as a string containing a decimal number. - - The amount is a positive number if it is credited to Increase (e.g., - settlements) and a negative number if it is debited (e.g., refunds). + """ + The interchange amount given as a string containing a decimal number in major + units (so e.g., "3.14" for $3.14). The amount is a positive number if it is + credited to Increase (e.g., settlements) and a negative number if it is debited + (e.g., refunds). """ code: Optional[str] = None @@ -1019,10 +1020,11 @@ class SourceCardSettlementCashback(BaseModel): class SourceCardSettlementInterchange(BaseModel): amount: str - """The interchange amount given as a string containing a decimal number. - - The amount is a positive number if it is credited to Increase (e.g., - settlements) and a negative number if it is debited (e.g., refunds). + """ + The interchange amount given as a string containing a decimal number in major + units (so e.g., "3.14" for $3.14). The amount is a positive number if it is + credited to Increase (e.g., settlements) and a negative number if it is debited + (e.g., refunds). """ code: Optional[str] = None diff --git a/tests/api_resources/test_check_transfers.py b/tests/api_resources/test_check_transfers.py index 772927741..a96bae822 100644 --- a/tests/api_resources/test_check_transfers.py +++ b/tests/api_resources/test_check_transfers.py @@ -48,6 +48,7 @@ def test_method_create_with_all_params(self, client: Increase) -> None: }, "memo": "Check payment", "recipient_name": "Ian Crease", + "attachment_file_id": "attachment_file_id", "check_number": "x", "note": "x", "return_address": { @@ -58,6 +59,7 @@ def test_method_create_with_all_params(self, client: Increase) -> None: "state": "x", "line2": "x", }, + "shipping_method": "usps_first_class", "signature_text": "Ian Crease", }, require_approval=True, @@ -331,6 +333,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncIncrease) }, "memo": "Check payment", "recipient_name": "Ian Crease", + "attachment_file_id": "attachment_file_id", "check_number": "x", "note": "x", "return_address": { @@ -341,6 +344,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncIncrease) "state": "x", "line2": "x", }, + "shipping_method": "usps_first_class", "signature_text": "Ian Crease", }, require_approval=True, diff --git a/tests/test_transform.py b/tests/test_transform.py index f100b2dc9..bb72d99a9 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -8,7 +8,7 @@ import pytest -from increase._types import Base64FileInput +from increase._types import NOT_GIVEN, Base64FileInput from increase._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) == {}