From 63a905c643203ca1e525f02f66b73800ecd83416 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:47:06 +0000 Subject: [PATCH 01/12] chore(internal): minor formatting changes (#580) --- .github/workflows/ci.yml | 3 +-- scripts/bootstrap | 2 +- scripts/lint | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40293964..c8a8a4f7 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 @@ -30,6 +29,7 @@ jobs: - name: Run lints run: ./scripts/lint + test: name: test runs-on: ubuntu-latest @@ -50,4 +50,3 @@ jobs: - name: Run tests run: ./scripts/test - diff --git a/scripts/bootstrap b/scripts/bootstrap index 8c5c60eb..e84fe62c 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if ! command -v rye >/dev/null 2>&1 && [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then brew bundle check >/dev/null 2>&1 || { echo "==> Installing Homebrew dependencies…" brew bundle diff --git a/scripts/lint b/scripts/lint index 9d53daa6..e5745bea 100755 --- a/scripts/lint +++ b/scripts/lint @@ -9,4 +9,3 @@ rye run lint echo "==> Making sure it imports" rye run python -c 'import finch' - From 29f6aff68071376bf24d01fd5f3f2098145bb970 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:19:18 +0000 Subject: [PATCH 02/12] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index fb18d036..83a48059 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 41 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-77520f5037161db86208e3a9d3f36f39e971a8ee10b1d9972a22c084fcf21845.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-0ff5b707b4e3afcf4020e2d4b71bb4d4cfb25eac2828d6de5bee8d4d5d81550d.yml From 1568147b9ba15f131b87d34fbb4b66f0049b160e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 21:02:16 +0000 Subject: [PATCH 03/12] feat(api): api update (#582) --- .stats.yml | 2 +- src/finch/resources/connect/sessions.py | 8 ++++---- src/finch/types/connect/session_new_params.py | 2 +- src/finch/types/connect/session_reauthenticate_params.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.stats.yml b/.stats.yml index 83a48059..a39ef663 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 41 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-0ff5b707b4e3afcf4020e2d4b71bb4d4cfb25eac2828d6de5bee8d4d5d81550d.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-9c0b41ca8713a9440c624b0d08de0e6cbd9486978188afab2286ae67d8a97817.yml diff --git a/src/finch/resources/connect/sessions.py b/src/finch/resources/connect/sessions.py index e878e2e5..f9d743d7 100644 --- a/src/finch/resources/connect/sessions.py +++ b/src/finch/resources/connect/sessions.py @@ -69,7 +69,7 @@ def new( Create a new connect session for an employer Args: - minutes_to_expire: The number of minutes until the session expires (defaults to 20,160, which is 14 + minutes_to_expire: The number of minutes until the session expires (defaults to 43,200, which is 30 days) extra_headers: Send extra headers @@ -129,7 +129,7 @@ def reauthenticate( Args: connection_id: The ID of the existing connection to reauthenticate - minutes_to_expire: The number of minutes until the session expires (defaults to 20,160, which is 14 + minutes_to_expire: The number of minutes until the session expires (defaults to 43,200, which is 30 days) products: The products to request access to (optional for reauthentication) @@ -207,7 +207,7 @@ async def new( Create a new connect session for an employer Args: - minutes_to_expire: The number of minutes until the session expires (defaults to 20,160, which is 14 + minutes_to_expire: The number of minutes until the session expires (defaults to 43,200, which is 30 days) extra_headers: Send extra headers @@ -267,7 +267,7 @@ async def reauthenticate( Args: connection_id: The ID of the existing connection to reauthenticate - minutes_to_expire: The number of minutes until the session expires (defaults to 20,160, which is 14 + minutes_to_expire: The number of minutes until the session expires (defaults to 43,200, which is 30 days) products: The products to request access to (optional for reauthentication) diff --git a/src/finch/types/connect/session_new_params.py b/src/finch/types/connect/session_new_params.py index f9dfef35..2eb43d86 100644 --- a/src/finch/types/connect/session_new_params.py +++ b/src/finch/types/connect/session_new_params.py @@ -25,7 +25,7 @@ class SessionNewParams(TypedDict, total=False): minutes_to_expire: Optional[float] """ - The number of minutes until the session expires (defaults to 20,160, which is 14 + The number of minutes until the session expires (defaults to 43,200, which is 30 days) """ diff --git a/src/finch/types/connect/session_reauthenticate_params.py b/src/finch/types/connect/session_reauthenticate_params.py index 2738eb7a..3a1c38b2 100644 --- a/src/finch/types/connect/session_reauthenticate_params.py +++ b/src/finch/types/connect/session_reauthenticate_params.py @@ -14,7 +14,7 @@ class SessionReauthenticateParams(TypedDict, total=False): minutes_to_expire: Optional[int] """ - The number of minutes until the session expires (defaults to 20,160, which is 14 + The number of minutes until the session expires (defaults to 43,200, which is 30 days) """ From a26a626a063c71cd055068a288ae53f543d73144 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 21:41:50 +0000 Subject: [PATCH 04/12] chore(internal): codegen related update (#583) --- src/finch/pagination.py | 48 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/finch/pagination.py b/src/finch/pagination.py index c2afd69f..dedacd1c 100644 --- a/src/finch/pagination.py +++ b/src/finch/pagination.py @@ -144,7 +144,17 @@ def next_page_info(self) -> Optional[PageInfo]: length = len(self._get_page_items()) current_count = offset + length - return PageInfo(params={"offset": current_count}) + count = None + if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison] + if self.paging.count is not None: + count = self.paging.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None class AsyncIndividualsPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): @@ -171,7 +181,17 @@ def next_page_info(self) -> Optional[PageInfo]: length = len(self._get_page_items()) current_count = offset + length - return PageInfo(params={"offset": current_count}) + count = None + if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison] + if self.paging.count is not None: + count = self.paging.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None class SyncPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): @@ -197,7 +217,17 @@ def next_page_info(self) -> Optional[PageInfo]: length = len(self._get_page_items()) current_count = offset + length - return PageInfo(params={"offset": current_count}) + count = None + if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison] + if self.paging.count is not None: + count = self.paging.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None class AsyncPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): @@ -223,4 +253,14 @@ def next_page_info(self) -> Optional[PageInfo]: length = len(self._get_page_items()) current_count = offset + length - return PageInfo(params={"offset": current_count}) + count = None + if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison] + if self.paging.count is not None: + count = self.paging.count + if count is None: + return None + + if current_count < count: + return PageInfo(params={"offset": current_count}) + + return None From 79bb13f68f07f41ef9342110bf481f3d134644a4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 17:44:13 +0000 Subject: [PATCH 05/12] feat(api): api update (#584) --- .stats.yml | 2 +- src/finch/resources/jobs/automated.py | 20 ++++++++----------- .../types/jobs/automated_create_params.py | 10 +++++++--- tests/api_resources/jobs/test_automated.py | 12 +++++------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.stats.yml b/.stats.yml index a39ef663..776ae867 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 41 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-9c0b41ca8713a9440c624b0d08de0e6cbd9486978188afab2286ae67d8a97817.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-33c66e078bce0755ba6ffea89b65cd065f406dae750be8a23dd0315b736f1c9f.yml diff --git a/src/finch/resources/jobs/automated.py b/src/finch/resources/jobs/automated.py index e3ccb1b2..ce3e70ca 100644 --- a/src/finch/resources/jobs/automated.py +++ b/src/finch/resources/jobs/automated.py @@ -90,7 +90,7 @@ def create( def create( self, *, - individual_id: str, + params: automated_create_params.W4FormEmployeeSyncParams, type: Literal["w4_form_employee_sync"], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -116,8 +116,6 @@ def create( access to this endpoint, please contact your Finch account manager. Args: - individual_id: The unique ID of the individual for W-4 data sync. - type: The type of job to start. extra_headers: Send extra headers @@ -130,12 +128,12 @@ def create( """ ... - @required_args(["type"], ["individual_id", "type"]) + @required_args(["type"], ["params", "type"]) def create( self, *, type: Literal["data_sync_all"] | Literal["w4_form_employee_sync"], - individual_id: str | NotGiven = NOT_GIVEN, + params: automated_create_params.W4FormEmployeeSyncParams | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -148,7 +146,7 @@ def create( body=maybe_transform( { "type": type, - "individual_id": individual_id, + "params": params, }, automated_create_params.AutomatedCreateParams, ), @@ -307,7 +305,7 @@ async def create( async def create( self, *, - individual_id: str, + params: automated_create_params.W4FormEmployeeSyncParams, type: Literal["w4_form_employee_sync"], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -333,8 +331,6 @@ async def create( access to this endpoint, please contact your Finch account manager. Args: - individual_id: The unique ID of the individual for W-4 data sync. - type: The type of job to start. extra_headers: Send extra headers @@ -347,12 +343,12 @@ async def create( """ ... - @required_args(["type"], ["individual_id", "type"]) + @required_args(["type"], ["params", "type"]) async def create( self, *, type: Literal["data_sync_all"] | Literal["w4_form_employee_sync"], - individual_id: str | NotGiven = NOT_GIVEN, + params: automated_create_params.W4FormEmployeeSyncParams | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -365,7 +361,7 @@ async def create( body=await async_maybe_transform( { "type": type, - "individual_id": individual_id, + "params": params, }, automated_create_params.AutomatedCreateParams, ), diff --git a/src/finch/types/jobs/automated_create_params.py b/src/finch/types/jobs/automated_create_params.py index 88b5c9ac..d7f7ec3b 100644 --- a/src/finch/types/jobs/automated_create_params.py +++ b/src/finch/types/jobs/automated_create_params.py @@ -5,7 +5,7 @@ from typing import Union from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["AutomatedCreateParams", "DataSyncAll", "W4FormEmployeeSync"] +__all__ = ["AutomatedCreateParams", "DataSyncAll", "W4FormEmployeeSync", "W4FormEmployeeSyncParams"] class DataSyncAll(TypedDict, total=False): @@ -14,11 +14,15 @@ class DataSyncAll(TypedDict, total=False): class W4FormEmployeeSync(TypedDict, total=False): - individual_id: Required[str] - """The unique ID of the individual for W-4 data sync.""" + params: Required[W4FormEmployeeSyncParams] type: Required[Literal["w4_form_employee_sync"]] """The type of job to start.""" +class W4FormEmployeeSyncParams(TypedDict, total=False): + individual_id: Required[str] + """The unique ID of the individual for W-4 data sync.""" + + AutomatedCreateParams: TypeAlias = Union[DataSyncAll, W4FormEmployeeSync] diff --git a/tests/api_resources/jobs/test_automated.py b/tests/api_resources/jobs/test_automated.py index c7571fa6..db83b0e5 100644 --- a/tests/api_resources/jobs/test_automated.py +++ b/tests/api_resources/jobs/test_automated.py @@ -52,7 +52,7 @@ def test_streaming_response_create_overload_1(self, client: Finch) -> None: @parametrize def test_method_create_overload_2(self, client: Finch) -> None: automated = client.jobs.automated.create( - individual_id="individual_id", + params={"individual_id": "individual_id"}, type="w4_form_employee_sync", ) assert_matches_type(AutomatedCreateResponse, automated, path=["response"]) @@ -60,7 +60,7 @@ def test_method_create_overload_2(self, client: Finch) -> None: @parametrize def test_raw_response_create_overload_2(self, client: Finch) -> None: response = client.jobs.automated.with_raw_response.create( - individual_id="individual_id", + params={"individual_id": "individual_id"}, type="w4_form_employee_sync", ) @@ -72,7 +72,7 @@ def test_raw_response_create_overload_2(self, client: Finch) -> None: @parametrize def test_streaming_response_create_overload_2(self, client: Finch) -> None: with client.jobs.automated.with_streaming_response.create( - individual_id="individual_id", + params={"individual_id": "individual_id"}, type="w4_form_employee_sync", ) as response: assert not response.is_closed @@ -192,7 +192,7 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncFin @parametrize async def test_method_create_overload_2(self, async_client: AsyncFinch) -> None: automated = await async_client.jobs.automated.create( - individual_id="individual_id", + params={"individual_id": "individual_id"}, type="w4_form_employee_sync", ) assert_matches_type(AutomatedCreateResponse, automated, path=["response"]) @@ -200,7 +200,7 @@ async def test_method_create_overload_2(self, async_client: AsyncFinch) -> None: @parametrize async def test_raw_response_create_overload_2(self, async_client: AsyncFinch) -> None: response = await async_client.jobs.automated.with_raw_response.create( - individual_id="individual_id", + params={"individual_id": "individual_id"}, type="w4_form_employee_sync", ) @@ -212,7 +212,7 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncFinch) -> @parametrize async def test_streaming_response_create_overload_2(self, async_client: AsyncFinch) -> None: async with async_client.jobs.automated.with_streaming_response.create( - individual_id="individual_id", + params={"individual_id": "individual_id"}, type="w4_form_employee_sync", ) as response: assert not response.is_closed From fe082cb9386df1bf4cd0e897505b8e7d750bd53b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 18:41:38 +0000 Subject: [PATCH 06/12] feat(api): api update (#585) --- .stats.yml | 2 +- src/finch/types/jobs/automated_async_job.py | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 776ae867..4068fd94 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 41 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-33c66e078bce0755ba6ffea89b65cd065f406dae750be8a23dd0315b736f1c9f.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-97bf4795deec23d1bfd3b0b5fd77c2a93c87f10e5fa3375ab30f4a877be97f53.yml diff --git a/src/finch/types/jobs/automated_async_job.py b/src/finch/types/jobs/automated_async_job.py index e9d75d8e..0c4ed460 100644 --- a/src/finch/types/jobs/automated_async_job.py +++ b/src/finch/types/jobs/automated_async_job.py @@ -6,7 +6,12 @@ from ..._models import BaseModel -__all__ = ["AutomatedAsyncJob"] +__all__ = ["AutomatedAsyncJob", "Params"] + + +class Params(BaseModel): + individual_id: Optional[str] = None + """The ID of the individual that the job was completed for.""" class AutomatedAsyncJob(BaseModel): @@ -26,6 +31,9 @@ class AutomatedAsyncJob(BaseModel): job_url: str """The url that can be used to retrieve the job status""" + params: Optional[Params] = None + """The input parameters for the job.""" + scheduled_at: Optional[datetime] = None """The datetime a job is scheduled to be run. @@ -38,5 +46,5 @@ class AutomatedAsyncJob(BaseModel): status: Literal["pending", "in_progress", "complete", "error", "reauth_error", "permissions_error"] - type: Literal["data_sync_all"] - """Only `data_sync_all` currently supported""" + type: Literal["data_sync_all", "w4_form_employee_sync"] + """The type of automated job""" From 4835451ae07ada92da7b531088d6a950f0009f63 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 14:41:04 +0000 Subject: [PATCH 07/12] chore(internal): change default timeout to an int (#586) --- src/finch/_constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/finch/_constants.py b/src/finch/_constants.py index a2ac3b6f..6ddf2c71 100644 --- a/src/finch/_constants.py +++ b/src/finch/_constants.py @@ -6,7 +6,7 @@ OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" # default timeout is 1 minute -DEFAULT_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0) +DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0) DEFAULT_MAX_RETRIES = 2 DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) From 592b7ccde3e2d8071aa030bde5cf24264b0d865b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:11:08 +0000 Subject: [PATCH 08/12] chore(internal): bummp ruff dependency (#587) --- pyproject.toml | 2 +- requirements-dev.lock | 2 +- scripts/utils/ruffen-docs.py | 4 ++-- src/finch/_models.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 62f04176..9ccd465c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -177,7 +177,7 @@ select = [ "T201", "T203", # misuse of typing.TYPE_CHECKING - "TCH004", + "TC004", # import rules "TID251", ] diff --git a/requirements-dev.lock b/requirements-dev.lock index feacfcaf..fe794e91 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -78,7 +78,7 @@ pytz==2023.3.post1 # via dirty-equals respx==0.22.0 rich==13.7.1 -ruff==0.6.9 +ruff==0.9.4 setuptools==68.2.2 # via nodeenv six==1.16.0 diff --git a/scripts/utils/ruffen-docs.py b/scripts/utils/ruffen-docs.py index 37b3d94f..0cf2bd2f 100644 --- a/scripts/utils/ruffen-docs.py +++ b/scripts/utils/ruffen-docs.py @@ -47,7 +47,7 @@ def _md_match(match: Match[str]) -> str: with _collect_error(match): code = format_code_block(code) code = textwrap.indent(code, match["indent"]) - return f'{match["before"]}{code}{match["after"]}' + return f"{match['before']}{code}{match['after']}" def _pycon_match(match: Match[str]) -> str: code = "" @@ -97,7 +97,7 @@ def finish_fragment() -> None: def _md_pycon_match(match: Match[str]) -> str: code = _pycon_match(match) code = textwrap.indent(code, match["indent"]) - return f'{match["before"]}{code}{match["after"]}' + return f"{match['before']}{code}{match['after']}" src = MD_RE.sub(_md_match, src) src = MD_PYCON_RE.sub(_md_pycon_match, src) diff --git a/src/finch/_models.py b/src/finch/_models.py index 9a918aab..12c34b7d 100644 --- a/src/finch/_models.py +++ b/src/finch/_models.py @@ -172,7 +172,7 @@ def to_json( @override def __str__(self) -> str: # mypy complains about an invalid self arg - return f'{self.__repr_name__()}({self.__repr_str__(", ")})' # type: ignore[misc] + return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] # Override the 'construct' method in a way that supports recursive parsing without validation. # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. From 70ca350878ae0e7b9f5c7ef4bbcd8f086cf91dd8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:12:38 +0000 Subject: [PATCH 09/12] feat(client): send `X-Stainless-Read-Timeout` header (#588) --- src/finch/_base_client.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/finch/_base_client.py b/src/finch/_base_client.py index b58fd57e..d9300541 100644 --- a/src/finch/_base_client.py +++ b/src/finch/_base_client.py @@ -419,10 +419,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 From b3157d73258d1a1976e6d9155f8b210e175de57c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:55:17 +0000 Subject: [PATCH 10/12] chore(internal): fix type traversing dictionary params (#589) --- src/finch/_utils/_transform.py | 12 +++++++++++- tests/test_transform.py | 11 ++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/finch/_utils/_transform.py b/src/finch/_utils/_transform.py index a6b62cad..18afd9d8 100644 --- a/src/finch/_utils/_transform.py +++ b/src/finch/_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/tests/test_transform.py b/tests/test_transform.py index cd713380..ad65c434 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")] From f37f226ff334f387a6c1a5fe1f1fa18c31533a47 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:19:55 +0000 Subject: [PATCH 11/12] chore(internal): minor type handling changes (#590) --- src/finch/_models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/finch/_models.py b/src/finch/_models.py index 12c34b7d..c4401ff8 100644 --- a/src/finch/_models.py +++ b/src/finch/_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 From a3266b674695322bafd5c1d3ec0ec2dc40bc114d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:21:02 +0000 Subject: [PATCH 12/12] release: 1.14.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 21 +++++++++++++++++++++ pyproject.toml | 2 +- src/finch/_version.py | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c4bf1b6c..e72f1131 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.13.3" + ".": "1.14.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a3f5f5f..c003d286 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 1.14.0 (2025-02-06) + +Full Changelog: [v1.13.3...v1.14.0](https://github.com/Finch-API/finch-api-python/compare/v1.13.3...v1.14.0) + +### Features + +* **api:** api update ([#582](https://github.com/Finch-API/finch-api-python/issues/582)) ([1568147](https://github.com/Finch-API/finch-api-python/commit/1568147b9ba15f131b87d34fbb4b66f0049b160e)) +* **api:** api update ([#584](https://github.com/Finch-API/finch-api-python/issues/584)) ([79bb13f](https://github.com/Finch-API/finch-api-python/commit/79bb13f68f07f41ef9342110bf481f3d134644a4)) +* **api:** api update ([#585](https://github.com/Finch-API/finch-api-python/issues/585)) ([fe082cb](https://github.com/Finch-API/finch-api-python/commit/fe082cb9386df1bf4cd0e897505b8e7d750bd53b)) +* **client:** send `X-Stainless-Read-Timeout` header ([#588](https://github.com/Finch-API/finch-api-python/issues/588)) ([70ca350](https://github.com/Finch-API/finch-api-python/commit/70ca350878ae0e7b9f5c7ef4bbcd8f086cf91dd8)) + + +### Chores + +* **internal:** bummp ruff dependency ([#587](https://github.com/Finch-API/finch-api-python/issues/587)) ([592b7cc](https://github.com/Finch-API/finch-api-python/commit/592b7ccde3e2d8071aa030bde5cf24264b0d865b)) +* **internal:** change default timeout to an int ([#586](https://github.com/Finch-API/finch-api-python/issues/586)) ([4835451](https://github.com/Finch-API/finch-api-python/commit/4835451ae07ada92da7b531088d6a950f0009f63)) +* **internal:** codegen related update ([#583](https://github.com/Finch-API/finch-api-python/issues/583)) ([a26a626](https://github.com/Finch-API/finch-api-python/commit/a26a626a063c71cd055068a288ae53f543d73144)) +* **internal:** fix type traversing dictionary params ([#589](https://github.com/Finch-API/finch-api-python/issues/589)) ([b3157d7](https://github.com/Finch-API/finch-api-python/commit/b3157d73258d1a1976e6d9155f8b210e175de57c)) +* **internal:** minor formatting changes ([#580](https://github.com/Finch-API/finch-api-python/issues/580)) ([63a905c](https://github.com/Finch-API/finch-api-python/commit/63a905c643203ca1e525f02f66b73800ecd83416)) +* **internal:** minor type handling changes ([#590](https://github.com/Finch-API/finch-api-python/issues/590)) ([f37f226](https://github.com/Finch-API/finch-api-python/commit/f37f226ff334f387a6c1a5fe1f1fa18c31533a47)) + ## 1.13.3 (2025-01-21) Full Changelog: [v1.13.2...v1.13.3](https://github.com/Finch-API/finch-api-python/compare/v1.13.2...v1.13.3) diff --git a/pyproject.toml b/pyproject.toml index 9ccd465c..026328d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "finch-api" -version = "1.13.3" +version = "1.14.0" description = "The official Python library for the Finch API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/finch/_version.py b/src/finch/_version.py index 58d395a6..1021bdca 100644 --- a/src/finch/_version.py +++ b/src/finch/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "finch" -__version__ = "1.13.3" # x-release-please-version +__version__ = "1.14.0" # x-release-please-version