diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 623b397aa..5ac298d4d 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.187.0"
+ ".": "0.188.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index d415aa66b..4803a266d 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
configured_endpoints: 201
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/increase%2Fincrease-ce741f23d99b551b38099da78d730af0cf9019e3b51e61bc988a5e5979c26143.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/increase%2Fincrease-f4db2590b8381f1ce20ef003e571392a1b33023e29febd4a3caca983705db688.yml
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 37c38845a..932b67ec6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# Changelog
+## 0.188.0 (2025-02-07)
+
+Full Changelog: [v0.187.0...v0.188.0](https://github.com/Increase/increase-python/compare/v0.187.0...v0.188.0)
+
+### Features
+
+* **api:** api update ([#956](https://github.com/Increase/increase-python/issues/956)) ([256d107](https://github.com/Increase/increase-python/commit/256d1075464dace95b926dc88f93864ffab19efe))
+* **api:** api update ([#957](https://github.com/Increase/increase-python/issues/957)) ([a8dfd3d](https://github.com/Increase/increase-python/commit/a8dfd3d326b715980f58ff983dd322082262bce5))
+* **client:** send `X-Stainless-Read-Timeout` header ([#952](https://github.com/Increase/increase-python/issues/952)) ([56c1cba](https://github.com/Increase/increase-python/commit/56c1cbac74b219e2a82d4c4088f6caae31fee502))
+
+
+### Chores
+
+* **internal:** fix type traversing dictionary params ([#954](https://github.com/Increase/increase-python/issues/954)) ([e0cc599](https://github.com/Increase/increase-python/commit/e0cc599129b55a5826bb3b61baab5c9973aee63f))
+* **internal:** minor type handling changes ([#955](https://github.com/Increase/increase-python/issues/955)) ([11f8788](https://github.com/Increase/increase-python/commit/11f87883da72091548389e386fa26203f6928199))
+
## 0.187.0 (2025-02-04)
Full Changelog: [v0.186.0...v0.187.0](https://github.com/Increase/increase-python/compare/v0.186.0...v0.187.0)
diff --git a/api.md b/api.md
index 846461cfc..40206ddf6 100644
--- a/api.md
+++ b/api.md
@@ -717,7 +717,7 @@ from increase.types import IntrafiBalance
Methods:
-- client.intrafi_balances.retrieve(account_id) -> IntrafiBalance
+- client.intrafi_balances.intrafi_balance(account_id) -> IntrafiBalance
# IntrafiExclusions
diff --git a/pyproject.toml b/pyproject.toml
index 4dcdf5865..d5cdc4520 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "increase"
-version = "0.187.0"
+version = "0.188.0"
description = "The official Python library for the increase API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/increase/_base_client.py b/src/increase/_base_client.py
index 40466184d..e8ba26a43 100644
--- a/src/increase/_base_client.py
+++ b/src/increase/_base_client.py
@@ -418,10 +418,17 @@ def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0
if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers:
headers[idempotency_header] = options.idempotency_key or self._idempotency_key()
- # Don't set the retry count header if it was already set or removed by the caller. We check
+ # Don't set these headers if they were already set or removed by the caller. We check
# `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case.
- if "x-stainless-retry-count" not in (header.lower() for header in custom_headers):
+ lower_custom_headers = [header.lower() for header in custom_headers]
+ if "x-stainless-retry-count" not in lower_custom_headers:
headers["x-stainless-retry-count"] = str(retries_taken)
+ if "x-stainless-read-timeout" not in lower_custom_headers:
+ timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout
+ if isinstance(timeout, Timeout):
+ timeout = timeout.read
+ if timeout is not None:
+ headers["x-stainless-read-timeout"] = str(timeout)
return headers
diff --git a/src/increase/_models.py b/src/increase/_models.py
index 12c34b7d1..c4401ff86 100644
--- a/src/increase/_models.py
+++ b/src/increase/_models.py
@@ -426,10 +426,16 @@ def construct_type(*, value: object, type_: object) -> object:
If the given value does not match the expected type then it is returned as-is.
"""
+
+ # store a reference to the original type we were given before we extract any inner
+ # types so that we can properly resolve forward references in `TypeAliasType` annotations
+ original_type = None
+
# we allow `object` as the input type because otherwise, passing things like
# `Literal['value']` will be reported as a type error by type checkers
type_ = cast("type[object]", type_)
if is_type_alias_type(type_):
+ original_type = type_ # type: ignore[unreachable]
type_ = type_.__value__ # type: ignore[unreachable]
# unwrap `Annotated[T, ...]` -> `T`
@@ -446,7 +452,7 @@ def construct_type(*, value: object, type_: object) -> object:
if is_union(origin):
try:
- return validate_type(type_=cast("type[object]", type_), value=value)
+ return validate_type(type_=cast("type[object]", original_type or type_), value=value)
except Exception:
pass
diff --git a/src/increase/_utils/_transform.py b/src/increase/_utils/_transform.py
index a6b62cad0..18afd9d8b 100644
--- a/src/increase/_utils/_transform.py
+++ b/src/increase/_utils/_transform.py
@@ -25,7 +25,7 @@
is_annotated_type,
strip_annotated_type,
)
-from .._compat import model_dump, is_typeddict
+from .._compat import get_origin, model_dump, is_typeddict
_T = TypeVar("_T")
@@ -164,9 +164,14 @@ def _transform_recursive(
inner_type = annotation
stripped_type = strip_annotated_type(inner_type)
+ origin = get_origin(stripped_type) or stripped_type
if is_typeddict(stripped_type) and is_mapping(data):
return _transform_typeddict(data, stripped_type)
+ if origin == dict and is_mapping(data):
+ items_type = get_args(stripped_type)[1]
+ return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()}
+
if (
# List[T]
(is_list_type(stripped_type) and is_list(data))
@@ -307,9 +312,14 @@ async def _async_transform_recursive(
inner_type = annotation
stripped_type = strip_annotated_type(inner_type)
+ origin = get_origin(stripped_type) or stripped_type
if is_typeddict(stripped_type) and is_mapping(data):
return await _async_transform_typeddict(data, stripped_type)
+ if origin == dict and is_mapping(data):
+ items_type = get_args(stripped_type)[1]
+ return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()}
+
if (
# List[T]
(is_list_type(stripped_type) and is_list(data))
diff --git a/src/increase/_version.py b/src/increase/_version.py
index 9e36aab94..00b84fe50 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.187.0" # x-release-please-version
+__version__ = "0.188.0" # x-release-please-version
diff --git a/src/increase/resources/intrafi_balances.py b/src/increase/resources/intrafi_balances.py
index cc9c517d5..a5b56f2b0 100644
--- a/src/increase/resources/intrafi_balances.py
+++ b/src/increase/resources/intrafi_balances.py
@@ -39,7 +39,7 @@ def with_streaming_response(self) -> IntrafiBalancesResourceWithStreamingRespons
"""
return IntrafiBalancesResourceWithStreamingResponse(self)
- def retrieve(
+ def intrafi_balance(
self,
account_id: str,
*,
@@ -67,7 +67,7 @@ def retrieve(
if not account_id:
raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}")
return self._get(
- f"/intrafi_balances/{account_id}",
+ f"/accounts/{account_id}/intrafi_balance",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -95,7 +95,7 @@ def with_streaming_response(self) -> AsyncIntrafiBalancesResourceWithStreamingRe
"""
return AsyncIntrafiBalancesResourceWithStreamingResponse(self)
- async def retrieve(
+ async def intrafi_balance(
self,
account_id: str,
*,
@@ -123,7 +123,7 @@ async def retrieve(
if not account_id:
raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}")
return await self._get(
- f"/intrafi_balances/{account_id}",
+ f"/accounts/{account_id}/intrafi_balance",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -135,8 +135,8 @@ class IntrafiBalancesResourceWithRawResponse:
def __init__(self, intrafi_balances: IntrafiBalancesResource) -> None:
self._intrafi_balances = intrafi_balances
- self.retrieve = to_raw_response_wrapper(
- intrafi_balances.retrieve,
+ self.intrafi_balance = to_raw_response_wrapper(
+ intrafi_balances.intrafi_balance,
)
@@ -144,8 +144,8 @@ class AsyncIntrafiBalancesResourceWithRawResponse:
def __init__(self, intrafi_balances: AsyncIntrafiBalancesResource) -> None:
self._intrafi_balances = intrafi_balances
- self.retrieve = async_to_raw_response_wrapper(
- intrafi_balances.retrieve,
+ self.intrafi_balance = async_to_raw_response_wrapper(
+ intrafi_balances.intrafi_balance,
)
@@ -153,8 +153,8 @@ class IntrafiBalancesResourceWithStreamingResponse:
def __init__(self, intrafi_balances: IntrafiBalancesResource) -> None:
self._intrafi_balances = intrafi_balances
- self.retrieve = to_streamed_response_wrapper(
- intrafi_balances.retrieve,
+ self.intrafi_balance = to_streamed_response_wrapper(
+ intrafi_balances.intrafi_balance,
)
@@ -162,6 +162,6 @@ class AsyncIntrafiBalancesResourceWithStreamingResponse:
def __init__(self, intrafi_balances: AsyncIntrafiBalancesResource) -> None:
self._intrafi_balances = intrafi_balances
- self.retrieve = async_to_streamed_response_wrapper(
- intrafi_balances.retrieve,
+ self.intrafi_balance = async_to_streamed_response_wrapper(
+ intrafi_balances.intrafi_balance,
)
diff --git a/src/increase/types/inbound_wire_transfer.py b/src/increase/types/inbound_wire_transfer.py
index c2d381d36..341f29679 100644
--- a/src/increase/types/inbound_wire_transfer.py
+++ b/src/increase/types/inbound_wire_transfer.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
+from datetime import datetime
from typing_extensions import Literal
from .._models import BaseModel
@@ -36,6 +37,12 @@ class InboundWireTransfer(BaseModel):
beneficiary_reference: Optional[str] = None
"""A free-form reference string set by the sender, to help identify the transfer."""
+ created_at: datetime
+ """
+ The [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date and time at which
+ the inbound wire transfer was created.
+ """
+
description: str
"""An Increase-constructed description of the transfer."""
diff --git a/src/increase/types/intrafi_account_enrollment.py b/src/increase/types/intrafi_account_enrollment.py
index 4f7eb73d5..b04e39136 100644
--- a/src/increase/types/intrafi_account_enrollment.py
+++ b/src/increase/types/intrafi_account_enrollment.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
+from datetime import datetime
from typing_extensions import Literal
from .._models import BaseModel
@@ -15,6 +16,12 @@ class IntrafiAccountEnrollment(BaseModel):
account_id: str
"""The identifier of the Increase Account being swept into the network."""
+ created_at: datetime
+ """
+ The [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date and time at which
+ the enrollment was created.
+ """
+
idempotency_key: Optional[str] = None
"""The idempotency key you chose for this object.
diff --git a/src/increase/types/intrafi_exclusion.py b/src/increase/types/intrafi_exclusion.py
index 6b1c35abd..c0a215fa7 100644
--- a/src/increase/types/intrafi_exclusion.py
+++ b/src/increase/types/intrafi_exclusion.py
@@ -16,6 +16,12 @@ class IntrafiExclusion(BaseModel):
bank_name: str
"""The name of the excluded institution."""
+ created_at: datetime
+ """
+ The [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date and time at which
+ the exclusion was created.
+ """
+
entity_id: str
"""The entity for which this institution is excluded."""
diff --git a/src/increase/types/wire_drawdown_request.py b/src/increase/types/wire_drawdown_request.py
index ac56aaa7f..b9c877167 100644
--- a/src/increase/types/wire_drawdown_request.py
+++ b/src/increase/types/wire_drawdown_request.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
+from datetime import datetime
from typing_extensions import Literal
from .._models import BaseModel
@@ -29,6 +30,12 @@ class WireDrawdownRequest(BaseModel):
amount: int
"""The amount being requested in cents."""
+ created_at: datetime
+ """
+ The [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date and time at which
+ the wire drawdown request was created.
+ """
+
currency: str
"""
The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) code for the amount being
diff --git a/tests/api_resources/test_intrafi_balances.py b/tests/api_resources/test_intrafi_balances.py
index 4e3f99c2b..6dd282615 100644
--- a/tests/api_resources/test_intrafi_balances.py
+++ b/tests/api_resources/test_intrafi_balances.py
@@ -18,15 +18,15 @@ class TestIntrafiBalances:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
@parametrize
- def test_method_retrieve(self, client: Increase) -> None:
- intrafi_balance = client.intrafi_balances.retrieve(
+ def test_method_intrafi_balance(self, client: Increase) -> None:
+ intrafi_balance = client.intrafi_balances.intrafi_balance(
"account_id",
)
assert_matches_type(IntrafiBalance, intrafi_balance, path=["response"])
@parametrize
- def test_raw_response_retrieve(self, client: Increase) -> None:
- response = client.intrafi_balances.with_raw_response.retrieve(
+ def test_raw_response_intrafi_balance(self, client: Increase) -> None:
+ response = client.intrafi_balances.with_raw_response.intrafi_balance(
"account_id",
)
@@ -36,8 +36,8 @@ def test_raw_response_retrieve(self, client: Increase) -> None:
assert_matches_type(IntrafiBalance, intrafi_balance, path=["response"])
@parametrize
- def test_streaming_response_retrieve(self, client: Increase) -> None:
- with client.intrafi_balances.with_streaming_response.retrieve(
+ def test_streaming_response_intrafi_balance(self, client: Increase) -> None:
+ with client.intrafi_balances.with_streaming_response.intrafi_balance(
"account_id",
) as response:
assert not response.is_closed
@@ -49,9 +49,9 @@ def test_streaming_response_retrieve(self, client: Increase) -> None:
assert cast(Any, response.is_closed) is True
@parametrize
- def test_path_params_retrieve(self, client: Increase) -> None:
+ def test_path_params_intrafi_balance(self, client: Increase) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
- client.intrafi_balances.with_raw_response.retrieve(
+ client.intrafi_balances.with_raw_response.intrafi_balance(
"",
)
@@ -60,15 +60,15 @@ class TestAsyncIntrafiBalances:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
@parametrize
- async def test_method_retrieve(self, async_client: AsyncIncrease) -> None:
- intrafi_balance = await async_client.intrafi_balances.retrieve(
+ async def test_method_intrafi_balance(self, async_client: AsyncIncrease) -> None:
+ intrafi_balance = await async_client.intrafi_balances.intrafi_balance(
"account_id",
)
assert_matches_type(IntrafiBalance, intrafi_balance, path=["response"])
@parametrize
- async def test_raw_response_retrieve(self, async_client: AsyncIncrease) -> None:
- response = await async_client.intrafi_balances.with_raw_response.retrieve(
+ async def test_raw_response_intrafi_balance(self, async_client: AsyncIncrease) -> None:
+ response = await async_client.intrafi_balances.with_raw_response.intrafi_balance(
"account_id",
)
@@ -78,8 +78,8 @@ async def test_raw_response_retrieve(self, async_client: AsyncIncrease) -> None:
assert_matches_type(IntrafiBalance, intrafi_balance, path=["response"])
@parametrize
- async def test_streaming_response_retrieve(self, async_client: AsyncIncrease) -> None:
- async with async_client.intrafi_balances.with_streaming_response.retrieve(
+ async def test_streaming_response_intrafi_balance(self, async_client: AsyncIncrease) -> None:
+ async with async_client.intrafi_balances.with_streaming_response.intrafi_balance(
"account_id",
) as response:
assert not response.is_closed
@@ -91,8 +91,8 @@ async def test_streaming_response_retrieve(self, async_client: AsyncIncrease) ->
assert cast(Any, response.is_closed) is True
@parametrize
- async def test_path_params_retrieve(self, async_client: AsyncIncrease) -> None:
+ async def test_path_params_intrafi_balance(self, async_client: AsyncIncrease) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
- await async_client.intrafi_balances.with_raw_response.retrieve(
+ await async_client.intrafi_balances.with_raw_response.intrafi_balance(
"",
)
diff --git a/tests/api_resources/test_oauth_connections.py b/tests/api_resources/test_oauth_connections.py
index d8e08b2d9..8c218df2f 100644
--- a/tests/api_resources/test_oauth_connections.py
+++ b/tests/api_resources/test_oauth_connections.py
@@ -21,14 +21,14 @@ class TestOAuthConnections:
@parametrize
def test_method_retrieve(self, client: Increase) -> None:
oauth_connection = client.oauth_connections.retrieve(
- "oauth_connection_id",
+ "x",
)
assert_matches_type(OAuthConnection, oauth_connection, path=["response"])
@parametrize
def test_raw_response_retrieve(self, client: Increase) -> None:
response = client.oauth_connections.with_raw_response.retrieve(
- "oauth_connection_id",
+ "x",
)
assert response.is_closed is True
@@ -39,7 +39,7 @@ def test_raw_response_retrieve(self, client: Increase) -> None:
@parametrize
def test_streaming_response_retrieve(self, client: Increase) -> None:
with client.oauth_connections.with_streaming_response.retrieve(
- "oauth_connection_id",
+ "x",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -98,14 +98,14 @@ class TestAsyncOAuthConnections:
@parametrize
async def test_method_retrieve(self, async_client: AsyncIncrease) -> None:
oauth_connection = await async_client.oauth_connections.retrieve(
- "oauth_connection_id",
+ "x",
)
assert_matches_type(OAuthConnection, oauth_connection, path=["response"])
@parametrize
async def test_raw_response_retrieve(self, async_client: AsyncIncrease) -> None:
response = await async_client.oauth_connections.with_raw_response.retrieve(
- "oauth_connection_id",
+ "x",
)
assert response.is_closed is True
@@ -116,7 +116,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncIncrease) -> None:
@parametrize
async def test_streaming_response_retrieve(self, async_client: AsyncIncrease) -> None:
async with async_client.oauth_connections.with_streaming_response.retrieve(
- "oauth_connection_id",
+ "x",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
diff --git a/tests/test_transform.py b/tests/test_transform.py
index 1f0743ce0..80c914329 100644
--- a/tests/test_transform.py
+++ b/tests/test_transform.py
@@ -2,7 +2,7 @@
import io
import pathlib
-from typing import Any, List, Union, TypeVar, Iterable, Optional, cast
+from typing import Any, Dict, List, Union, TypeVar, Iterable, Optional, cast
from datetime import date, datetime
from typing_extensions import Required, Annotated, TypedDict
@@ -388,6 +388,15 @@ def my_iter() -> Iterable[Baz8]:
}
+@parametrize
+@pytest.mark.asyncio
+async def test_dictionary_items(use_async: bool) -> None:
+ class DictItems(TypedDict):
+ foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")]
+
+ assert await transform({"foo": {"foo_baz": "bar"}}, Dict[str, DictItems], use_async) == {"foo": {"fooBaz": "bar"}}
+
+
class TypedDictIterableUnionStr(TypedDict):
foo: Annotated[Union[str, Iterable[Baz8]], PropertyInfo(alias="FOO")]