From 3bd22fe8a9fe02f2700ac0b6387b00575cddc444 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 18 Mar 2024 20:51:33 +0000
Subject: [PATCH 01/13] perf: cache TypeAdapters (#324)
---
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 88afa408..16697353 100644
--- a/src/finch/_models.py
+++ b/src/finch/_models.py
@@ -3,6 +3,7 @@
import inspect
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast
from datetime import date, datetime
+from functools import lru_cache
from typing_extensions import (
Unpack,
Literal,
@@ -533,7 +534,12 @@ class GenericModel(BaseGenericModel, BaseModel):
if PYDANTIC_V2:
- from pydantic import TypeAdapter
+ if TYPE_CHECKING:
+ from pydantic import TypeAdapter
+ else:
+ from pydantic import TypeAdapter as _TypeAdapter
+
+ TypeAdapter = lru_cache(_TypeAdapter)
def _validate_non_model_type(*, type_: type[_T], value: object) -> _T:
return TypeAdapter(type_).validate_python(value)
From 98ba71b32ab2eaa1564b0fbab85cb2de9a0ea421 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 19 Mar 2024 02:26:41 +0000
Subject: [PATCH 02/13] docs: fix typo in CONTRIBUTING.md (#326)
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 265c3ac7..c6bf27ef 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -86,7 +86,7 @@ Most tests require you to [set up a mock server](https://github.com/stoplightio/
```bash
# you will need npm installed
-npx prism path/to/your/openapi.yml
+npx prism mock path/to/your/openapi.yml
```
```bash
From 269569fdca6c03dc8202dab0b20e00c099020d65 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 19 Mar 2024 10:41:23 +0000
Subject: [PATCH 03/13] chore(internal): update generated pragma comment (#327)
---
src/finch/__init__.py | 2 +-
src/finch/_client.py | 2 +-
src/finch/_constants.py | 2 +-
src/finch/_exceptions.py | 2 +-
src/finch/_resource.py | 2 +-
src/finch/_version.py | 2 +-
src/finch/pagination.py | 2 +-
src/finch/resources/__init__.py | 2 +-
src/finch/resources/access_tokens.py | 2 +-
src/finch/resources/account.py | 2 +-
src/finch/resources/hris/__init__.py | 2 +-
src/finch/resources/hris/benefits/__init__.py | 2 +-
src/finch/resources/hris/benefits/benefits.py | 2 +-
src/finch/resources/hris/benefits/individuals.py | 2 +-
src/finch/resources/hris/company.py | 2 +-
src/finch/resources/hris/directory.py | 2 +-
src/finch/resources/hris/employments.py | 2 +-
src/finch/resources/hris/hris.py | 2 +-
src/finch/resources/hris/individuals.py | 2 +-
src/finch/resources/hris/pay_statements.py | 2 +-
src/finch/resources/hris/payments.py | 2 +-
src/finch/resources/jobs/__init__.py | 2 +-
src/finch/resources/jobs/automated.py | 2 +-
src/finch/resources/jobs/jobs.py | 2 +-
src/finch/resources/jobs/manual.py | 2 +-
src/finch/resources/providers.py | 2 +-
src/finch/resources/request_forwarding.py | 2 +-
src/finch/resources/sandbox/__init__.py | 2 +-
src/finch/resources/sandbox/company.py | 2 +-
src/finch/resources/sandbox/connections/__init__.py | 2 +-
src/finch/resources/sandbox/connections/accounts.py | 2 +-
src/finch/resources/sandbox/connections/connections.py | 2 +-
src/finch/resources/sandbox/directory.py | 2 +-
src/finch/resources/sandbox/employment.py | 2 +-
src/finch/resources/sandbox/individual.py | 2 +-
src/finch/resources/sandbox/jobs/__init__.py | 2 +-
src/finch/resources/sandbox/jobs/configuration.py | 2 +-
src/finch/resources/sandbox/jobs/jobs.py | 2 +-
src/finch/resources/sandbox/payment.py | 2 +-
src/finch/resources/sandbox/sandbox.py | 2 +-
src/finch/resources/webhooks.py | 2 +-
src/finch/types/__init__.py | 2 +-
src/finch/types/access_token_create_params.py | 2 +-
src/finch/types/account_update_event.py | 2 +-
src/finch/types/base_webhook_event.py | 2 +-
src/finch/types/company_event.py | 2 +-
src/finch/types/create_access_token_response.py | 2 +-
src/finch/types/directory_event.py | 2 +-
src/finch/types/disconnect_response.py | 2 +-
src/finch/types/employment_event.py | 2 +-
src/finch/types/hris/__init__.py | 2 +-
src/finch/types/hris/benefit_contribution.py | 2 +-
src/finch/types/hris/benefit_create_params.py | 2 +-
src/finch/types/hris/benefit_features_and_operations.py | 2 +-
src/finch/types/hris/benefit_frequency.py | 2 +-
src/finch/types/hris/benefit_type.py | 2 +-
src/finch/types/hris/benefit_update_params.py | 2 +-
src/finch/types/hris/benefits/__init__.py | 2 +-
src/finch/types/hris/benefits/enrolled_individual.py | 2 +-
src/finch/types/hris/benefits/individual_benefit.py | 2 +-
src/finch/types/hris/benefits/individual_enroll_many_params.py | 2 +-
.../types/hris/benefits/individual_enrolled_ids_response.py | 2 +-
.../hris/benefits/individual_retrieve_many_benefits_params.py | 2 +-
.../types/hris/benefits/individual_unenroll_many_params.py | 2 +-
src/finch/types/hris/benefits/unenrolled_individual.py | 2 +-
src/finch/types/hris/benefits_support.py | 2 +-
src/finch/types/hris/benfit_contribution.py | 2 +-
src/finch/types/hris/company.py | 2 +-
src/finch/types/hris/company_benefit.py | 2 +-
src/finch/types/hris/create_company_benefits_response.py | 2 +-
src/finch/types/hris/directory_list_individuals_params.py | 2 +-
src/finch/types/hris/directory_list_params.py | 2 +-
src/finch/types/hris/employment_data.py | 2 +-
src/finch/types/hris/employment_data_response.py | 2 +-
src/finch/types/hris/employment_retrieve_many_params.py | 2 +-
src/finch/types/hris/individual.py | 2 +-
src/finch/types/hris/individual_in_directory.py | 2 +-
src/finch/types/hris/individual_response.py | 2 +-
src/finch/types/hris/individual_retrieve_many_params.py | 2 +-
src/finch/types/hris/pay_statement.py | 2 +-
src/finch/types/hris/pay_statement_response.py | 2 +-
src/finch/types/hris/pay_statement_response_body.py | 2 +-
src/finch/types/hris/pay_statement_retrieve_many_params.py | 2 +-
src/finch/types/hris/payment.py | 2 +-
src/finch/types/hris/payment_list_params.py | 2 +-
src/finch/types/hris/support_per_benefit_type.py | 2 +-
src/finch/types/hris/supported_benefit.py | 2 +-
src/finch/types/hris/update_company_benefit_response.py | 2 +-
src/finch/types/income.py | 2 +-
src/finch/types/income_param.py | 2 +-
src/finch/types/individual_event.py | 2 +-
src/finch/types/introspection.py | 2 +-
src/finch/types/job_completion_event.py | 2 +-
src/finch/types/jobs/__init__.py | 2 +-
src/finch/types/jobs/automated_async_job.py | 2 +-
src/finch/types/jobs/automated_create_params.py | 2 +-
src/finch/types/jobs/automated_create_response.py | 2 +-
src/finch/types/jobs/automated_list_params.py | 2 +-
src/finch/types/jobs/manual_async_job.py | 2 +-
src/finch/types/location.py | 2 +-
src/finch/types/location_param.py | 2 +-
src/finch/types/money.py | 2 +-
src/finch/types/money_param.py | 2 +-
src/finch/types/pay_statement_event.py | 2 +-
src/finch/types/payment_event.py | 2 +-
src/finch/types/provider.py | 2 +-
src/finch/types/request_forwarding_forward_params.py | 2 +-
src/finch/types/request_forwarding_forward_response.py | 2 +-
src/finch/types/sandbox/__init__.py | 2 +-
src/finch/types/sandbox/company_update_params.py | 2 +-
src/finch/types/sandbox/company_update_response.py | 2 +-
src/finch/types/sandbox/connection_create_params.py | 2 +-
src/finch/types/sandbox/connection_create_response.py | 2 +-
src/finch/types/sandbox/connections/__init__.py | 2 +-
src/finch/types/sandbox/connections/account_create_params.py | 2 +-
src/finch/types/sandbox/connections/account_create_response.py | 2 +-
src/finch/types/sandbox/connections/account_update_params.py | 2 +-
src/finch/types/sandbox/connections/account_update_response.py | 2 +-
src/finch/types/sandbox/directory_create_params.py | 2 +-
src/finch/types/sandbox/directory_create_response.py | 2 +-
src/finch/types/sandbox/employment_update_params.py | 2 +-
src/finch/types/sandbox/employment_update_response.py | 2 +-
src/finch/types/sandbox/individual_update_params.py | 2 +-
src/finch/types/sandbox/individual_update_response.py | 2 +-
src/finch/types/sandbox/job_create_params.py | 2 +-
src/finch/types/sandbox/job_create_response.py | 2 +-
src/finch/types/sandbox/jobs/__init__.py | 2 +-
src/finch/types/sandbox/jobs/configuration_retrieve_response.py | 2 +-
src/finch/types/sandbox/jobs/configuration_update_params.py | 2 +-
src/finch/types/sandbox/jobs/sandbox_job_configuration.py | 2 +-
src/finch/types/sandbox/payment_create_params.py | 2 +-
src/finch/types/sandbox/payment_create_response.py | 2 +-
src/finch/types/shared/__init__.py | 2 +-
src/finch/types/shared/connection_status_type.py | 2 +-
src/finch/types/shared/operation_support.py | 2 +-
src/finch/types/shared/operation_support_matrix.py | 2 +-
src/finch/types/shared/paging.py | 2 +-
src/finch/types/shared_params/__init__.py | 2 +-
src/finch/types/shared_params/connection_status_type.py | 2 +-
src/finch/types/webhook_event.py | 2 +-
tests/__init__.py | 2 +-
tests/api_resources/__init__.py | 2 +-
tests/api_resources/hris/__init__.py | 2 +-
tests/api_resources/hris/benefits/__init__.py | 2 +-
tests/api_resources/hris/benefits/test_individuals.py | 2 +-
tests/api_resources/hris/test_benefits.py | 2 +-
tests/api_resources/hris/test_company.py | 2 +-
tests/api_resources/hris/test_directory.py | 2 +-
tests/api_resources/hris/test_employments.py | 2 +-
tests/api_resources/hris/test_individuals.py | 2 +-
tests/api_resources/hris/test_pay_statements.py | 2 +-
tests/api_resources/hris/test_payments.py | 2 +-
tests/api_resources/jobs/__init__.py | 2 +-
tests/api_resources/jobs/test_automated.py | 2 +-
tests/api_resources/jobs/test_manual.py | 2 +-
tests/api_resources/sandbox/__init__.py | 2 +-
tests/api_resources/sandbox/connections/__init__.py | 2 +-
tests/api_resources/sandbox/connections/test_accounts.py | 2 +-
tests/api_resources/sandbox/jobs/__init__.py | 2 +-
tests/api_resources/sandbox/jobs/test_configuration.py | 2 +-
tests/api_resources/sandbox/test_company.py | 2 +-
tests/api_resources/sandbox/test_connections.py | 2 +-
tests/api_resources/sandbox/test_directory.py | 2 +-
tests/api_resources/sandbox/test_employment.py | 2 +-
tests/api_resources/sandbox/test_individual.py | 2 +-
tests/api_resources/sandbox/test_jobs.py | 2 +-
tests/api_resources/sandbox/test_payment.py | 2 +-
tests/api_resources/test_access_tokens.py | 2 +-
tests/api_resources/test_account.py | 2 +-
tests/api_resources/test_providers.py | 2 +-
tests/api_resources/test_request_forwarding.py | 2 +-
tests/api_resources/test_top_level.py | 2 +-
tests/api_resources/test_webhooks.py | 2 +-
tests/test_client.py | 2 +-
174 files changed, 174 insertions(+), 174 deletions(-)
diff --git a/src/finch/__init__.py b/src/finch/__init__.py
index 275a5e1f..4f268071 100644
--- a/src/finch/__init__.py
+++ b/src/finch/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from . import types
from ._types import NOT_GIVEN, NoneType, NotGiven, Transport, ProxiesTypes
diff --git a/src/finch/_client.py b/src/finch/_client.py
index c86d8e35..cddb281d 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/_constants.py b/src/finch/_constants.py
index bf15141a..1d56f7fd 100644
--- a/src/finch/_constants.py
+++ b/src/finch/_constants.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
import httpx
diff --git a/src/finch/_exceptions.py b/src/finch/_exceptions.py
index ba7b00fa..0690570c 100644
--- a/src/finch/_exceptions.py
+++ b/src/finch/_exceptions.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/_resource.py b/src/finch/_resource.py
index 99f728b6..ff3e89ca 100644
--- a/src/finch/_resource.py
+++ b/src/finch/_resource.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/_version.py b/src/finch/_version.py
index a1ad996f..3cb66124 100644
--- a/src/finch/_version.py
+++ b/src/finch/_version.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "finch"
__version__ = "0.16.8" # x-release-please-version
diff --git a/src/finch/pagination.py b/src/finch/pagination.py
index e878ab44..c90207a3 100644
--- a/src/finch/pagination.py
+++ b/src/finch/pagination.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Any, List, Type, Generic, Mapping, TypeVar, Optional, cast
from typing_extensions import override
diff --git a/src/finch/resources/__init__.py b/src/finch/resources/__init__.py
index 13ad3da5..d5f226e9 100644
--- a/src/finch/resources/__init__.py
+++ b/src/finch/resources/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .hris import (
HRIS,
diff --git a/src/finch/resources/access_tokens.py b/src/finch/resources/access_tokens.py
index 8ab710c1..7e4fad17 100644
--- a/src/finch/resources/access_tokens.py
+++ b/src/finch/resources/access_tokens.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/account.py b/src/finch/resources/account.py
index ddb7f166..81ed126b 100644
--- a/src/finch/resources/account.py
+++ b/src/finch/resources/account.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/__init__.py b/src/finch/resources/hris/__init__.py
index 3eea83c6..969b31f5 100644
--- a/src/finch/resources/hris/__init__.py
+++ b/src/finch/resources/hris/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .hris import (
HRIS,
diff --git a/src/finch/resources/hris/benefits/__init__.py b/src/finch/resources/hris/benefits/__init__.py
index 07a79df6..4b7758aa 100644
--- a/src/finch/resources/hris/benefits/__init__.py
+++ b/src/finch/resources/hris/benefits/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .benefits import (
Benefits,
diff --git a/src/finch/resources/hris/benefits/benefits.py b/src/finch/resources/hris/benefits/benefits.py
index c8b6884b..a35baa5b 100644
--- a/src/finch/resources/hris/benefits/benefits.py
+++ b/src/finch/resources/hris/benefits/benefits.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/benefits/individuals.py b/src/finch/resources/hris/benefits/individuals.py
index f2dcdf50..f3a49bbe 100644
--- a/src/finch/resources/hris/benefits/individuals.py
+++ b/src/finch/resources/hris/benefits/individuals.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/company.py b/src/finch/resources/hris/company.py
index 9180ef32..dd84b156 100644
--- a/src/finch/resources/hris/company.py
+++ b/src/finch/resources/hris/company.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/directory.py b/src/finch/resources/hris/directory.py
index 4a9ac9b6..cacfc87c 100644
--- a/src/finch/resources/hris/directory.py
+++ b/src/finch/resources/hris/directory.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/employments.py b/src/finch/resources/hris/employments.py
index fcc6a69d..2c516663 100644
--- a/src/finch/resources/hris/employments.py
+++ b/src/finch/resources/hris/employments.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/hris.py b/src/finch/resources/hris/hris.py
index 8fd5751b..8a49bc85 100644
--- a/src/finch/resources/hris/hris.py
+++ b/src/finch/resources/hris/hris.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/individuals.py b/src/finch/resources/hris/individuals.py
index 24dae227..ff130b5b 100644
--- a/src/finch/resources/hris/individuals.py
+++ b/src/finch/resources/hris/individuals.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/pay_statements.py b/src/finch/resources/hris/pay_statements.py
index 9e1f7bc4..dd229e4c 100644
--- a/src/finch/resources/hris/pay_statements.py
+++ b/src/finch/resources/hris/pay_statements.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/hris/payments.py b/src/finch/resources/hris/payments.py
index 66496a99..6392133a 100644
--- a/src/finch/resources/hris/payments.py
+++ b/src/finch/resources/hris/payments.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/jobs/__init__.py b/src/finch/resources/jobs/__init__.py
index 261436d7..5ed454ad 100644
--- a/src/finch/resources/jobs/__init__.py
+++ b/src/finch/resources/jobs/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .jobs import (
Jobs,
diff --git a/src/finch/resources/jobs/automated.py b/src/finch/resources/jobs/automated.py
index d2818e0b..9068ce1c 100644
--- a/src/finch/resources/jobs/automated.py
+++ b/src/finch/resources/jobs/automated.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/jobs/jobs.py b/src/finch/resources/jobs/jobs.py
index ec354abd..950f977f 100644
--- a/src/finch/resources/jobs/jobs.py
+++ b/src/finch/resources/jobs/jobs.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/jobs/manual.py b/src/finch/resources/jobs/manual.py
index 03195ea2..81fd40a7 100644
--- a/src/finch/resources/jobs/manual.py
+++ b/src/finch/resources/jobs/manual.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/providers.py b/src/finch/resources/providers.py
index 63a671f4..4a37ee46 100644
--- a/src/finch/resources/providers.py
+++ b/src/finch/resources/providers.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/request_forwarding.py b/src/finch/resources/request_forwarding.py
index 31e9472d..337f85e1 100644
--- a/src/finch/resources/request_forwarding.py
+++ b/src/finch/resources/request_forwarding.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/__init__.py b/src/finch/resources/sandbox/__init__.py
index 0c8d6436..c738fb57 100644
--- a/src/finch/resources/sandbox/__init__.py
+++ b/src/finch/resources/sandbox/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .jobs import (
Jobs,
diff --git a/src/finch/resources/sandbox/company.py b/src/finch/resources/sandbox/company.py
index 267055b4..7c528a2b 100644
--- a/src/finch/resources/sandbox/company.py
+++ b/src/finch/resources/sandbox/company.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/connections/__init__.py b/src/finch/resources/sandbox/connections/__init__.py
index 053ae309..946f5ae5 100644
--- a/src/finch/resources/sandbox/connections/__init__.py
+++ b/src/finch/resources/sandbox/connections/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .accounts import (
Accounts,
diff --git a/src/finch/resources/sandbox/connections/accounts.py b/src/finch/resources/sandbox/connections/accounts.py
index 46cc1b77..b472adab 100644
--- a/src/finch/resources/sandbox/connections/accounts.py
+++ b/src/finch/resources/sandbox/connections/accounts.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/connections/connections.py b/src/finch/resources/sandbox/connections/connections.py
index 9a5f4b83..4e86bcd5 100644
--- a/src/finch/resources/sandbox/connections/connections.py
+++ b/src/finch/resources/sandbox/connections/connections.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/directory.py b/src/finch/resources/sandbox/directory.py
index 1de04caa..b46787bf 100644
--- a/src/finch/resources/sandbox/directory.py
+++ b/src/finch/resources/sandbox/directory.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/employment.py b/src/finch/resources/sandbox/employment.py
index 0c71d804..f4771306 100644
--- a/src/finch/resources/sandbox/employment.py
+++ b/src/finch/resources/sandbox/employment.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/individual.py b/src/finch/resources/sandbox/individual.py
index 68d0fb4a..32c75585 100644
--- a/src/finch/resources/sandbox/individual.py
+++ b/src/finch/resources/sandbox/individual.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/jobs/__init__.py b/src/finch/resources/sandbox/jobs/__init__.py
index c4f1bba4..7c90eeda 100644
--- a/src/finch/resources/sandbox/jobs/__init__.py
+++ b/src/finch/resources/sandbox/jobs/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .jobs import (
Jobs,
diff --git a/src/finch/resources/sandbox/jobs/configuration.py b/src/finch/resources/sandbox/jobs/configuration.py
index 9f6e53d8..bb8d159f 100644
--- a/src/finch/resources/sandbox/jobs/configuration.py
+++ b/src/finch/resources/sandbox/jobs/configuration.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/jobs/jobs.py b/src/finch/resources/sandbox/jobs/jobs.py
index cd7b2f3f..e504210b 100644
--- a/src/finch/resources/sandbox/jobs/jobs.py
+++ b/src/finch/resources/sandbox/jobs/jobs.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/payment.py b/src/finch/resources/sandbox/payment.py
index 471e67c9..678d24e8 100644
--- a/src/finch/resources/sandbox/payment.py
+++ b/src/finch/resources/sandbox/payment.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/sandbox/sandbox.py b/src/finch/resources/sandbox/sandbox.py
index 9daf72aa..d4b5a8d2 100644
--- a/src/finch/resources/sandbox/sandbox.py
+++ b/src/finch/resources/sandbox/sandbox.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/resources/webhooks.py b/src/finch/resources/webhooks.py
index 6f6d5b93..0fe50944 100644
--- a/src/finch/resources/webhooks.py
+++ b/src/finch/resources/webhooks.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/__init__.py b/src/finch/types/__init__.py
index da3b0ba0..4c2b5d4e 100644
--- a/src/finch/types/__init__.py
+++ b/src/finch/types/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/access_token_create_params.py b/src/finch/types/access_token_create_params.py
index 5935703f..85fcb158 100644
--- a/src/finch/types/access_token_create_params.py
+++ b/src/finch/types/access_token_create_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/account_update_event.py b/src/finch/types/account_update_event.py
index 449da582..eca89e1a 100644
--- a/src/finch/types/account_update_event.py
+++ b/src/finch/types/account_update_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/base_webhook_event.py b/src/finch/types/base_webhook_event.py
index efdc2818..2b9561d1 100644
--- a/src/finch/types/base_webhook_event.py
+++ b/src/finch/types/base_webhook_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .._models import BaseModel
diff --git a/src/finch/types/company_event.py b/src/finch/types/company_event.py
index 65c29060..bb69a7ef 100644
--- a/src/finch/types/company_event.py
+++ b/src/finch/types/company_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Dict, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/create_access_token_response.py b/src/finch/types/create_access_token_response.py
index 5b017fc2..494a1f74 100644
--- a/src/finch/types/create_access_token_response.py
+++ b/src/finch/types/create_access_token_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .._models import BaseModel
diff --git a/src/finch/types/directory_event.py b/src/finch/types/directory_event.py
index 863a6b43..ec5f399e 100644
--- a/src/finch/types/directory_event.py
+++ b/src/finch/types/directory_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/disconnect_response.py b/src/finch/types/disconnect_response.py
index f33e239b..2d128175 100644
--- a/src/finch/types/disconnect_response.py
+++ b/src/finch/types/disconnect_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .._models import BaseModel
diff --git a/src/finch/types/employment_event.py b/src/finch/types/employment_event.py
index 09d95428..4d630127 100644
--- a/src/finch/types/employment_event.py
+++ b/src/finch/types/employment_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/__init__.py b/src/finch/types/hris/__init__.py
index 0234b44b..75802659 100644
--- a/src/finch/types/hris/__init__.py
+++ b/src/finch/types/hris/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/benefit_contribution.py b/src/finch/types/hris/benefit_contribution.py
index 48ecc288..66423a85 100644
--- a/src/finch/types/hris/benefit_contribution.py
+++ b/src/finch/types/hris/benefit_contribution.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/benefit_create_params.py b/src/finch/types/hris/benefit_create_params.py
index e42f3bb0..efea46a5 100644
--- a/src/finch/types/hris/benefit_create_params.py
+++ b/src/finch/types/hris/benefit_create_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/benefit_features_and_operations.py b/src/finch/types/hris/benefit_features_and_operations.py
index 78fc27b3..cb763e62 100644
--- a/src/finch/types/hris/benefit_features_and_operations.py
+++ b/src/finch/types/hris/benefit_features_and_operations.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/benefit_frequency.py b/src/finch/types/hris/benefit_frequency.py
index 515774fe..e1d56e94 100644
--- a/src/finch/types/hris/benefit_frequency.py
+++ b/src/finch/types/hris/benefit_frequency.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/benefit_type.py b/src/finch/types/hris/benefit_type.py
index 81735c9c..d578f2f9 100644
--- a/src/finch/types/hris/benefit_type.py
+++ b/src/finch/types/hris/benefit_type.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/benefit_update_params.py b/src/finch/types/hris/benefit_update_params.py
index 00abf779..33ddfff2 100644
--- a/src/finch/types/hris/benefit_update_params.py
+++ b/src/finch/types/hris/benefit_update_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/benefits/__init__.py b/src/finch/types/hris/benefits/__init__.py
index 0d548269..4cca9ced 100644
--- a/src/finch/types/hris/benefits/__init__.py
+++ b/src/finch/types/hris/benefits/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/benefits/enrolled_individual.py b/src/finch/types/hris/benefits/enrolled_individual.py
index ae9cda73..5efb196b 100644
--- a/src/finch/types/hris/benefits/enrolled_individual.py
+++ b/src/finch/types/hris/benefits/enrolled_individual.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/benefits/individual_benefit.py b/src/finch/types/hris/benefits/individual_benefit.py
index 1016cf1c..9d4ff80a 100644
--- a/src/finch/types/hris/benefits/individual_benefit.py
+++ b/src/finch/types/hris/benefits/individual_benefit.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/benefits/individual_enroll_many_params.py b/src/finch/types/hris/benefits/individual_enroll_many_params.py
index 996ede7c..857de1b9 100644
--- a/src/finch/types/hris/benefits/individual_enroll_many_params.py
+++ b/src/finch/types/hris/benefits/individual_enroll_many_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/benefits/individual_enrolled_ids_response.py b/src/finch/types/hris/benefits/individual_enrolled_ids_response.py
index a7281461..c2c74002 100644
--- a/src/finch/types/hris/benefits/individual_enrolled_ids_response.py
+++ b/src/finch/types/hris/benefits/individual_enrolled_ids_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List
diff --git a/src/finch/types/hris/benefits/individual_retrieve_many_benefits_params.py b/src/finch/types/hris/benefits/individual_retrieve_many_benefits_params.py
index 6905dac9..dab473e1 100644
--- a/src/finch/types/hris/benefits/individual_retrieve_many_benefits_params.py
+++ b/src/finch/types/hris/benefits/individual_retrieve_many_benefits_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/benefits/individual_unenroll_many_params.py b/src/finch/types/hris/benefits/individual_unenroll_many_params.py
index fc1bc982..01f8b33e 100644
--- a/src/finch/types/hris/benefits/individual_unenroll_many_params.py
+++ b/src/finch/types/hris/benefits/individual_unenroll_many_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/benefits/unenrolled_individual.py b/src/finch/types/hris/benefits/unenrolled_individual.py
index 11c75ca0..d9f10497 100644
--- a/src/finch/types/hris/benefits/unenrolled_individual.py
+++ b/src/finch/types/hris/benefits/unenrolled_individual.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/hris/benefits_support.py b/src/finch/types/hris/benefits_support.py
index 7cf88efa..4632a969 100644
--- a/src/finch/types/hris/benefits_support.py
+++ b/src/finch/types/hris/benefits_support.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import TYPE_CHECKING, Optional
diff --git a/src/finch/types/hris/benfit_contribution.py b/src/finch/types/hris/benfit_contribution.py
index b3bee5cb..f9655532 100644
--- a/src/finch/types/hris/benfit_contribution.py
+++ b/src/finch/types/hris/benfit_contribution.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/src/finch/types/hris/company.py b/src/finch/types/hris/company.py
index f87ef3fc..3300ad0f 100644
--- a/src/finch/types/hris/company.py
+++ b/src/finch/types/hris/company.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/company_benefit.py b/src/finch/types/hris/company_benefit.py
index 84a36bc3..642642ba 100644
--- a/src/finch/types/hris/company_benefit.py
+++ b/src/finch/types/hris/company_benefit.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/hris/create_company_benefits_response.py b/src/finch/types/hris/create_company_benefits_response.py
index 473ff89c..9e5ff39b 100644
--- a/src/finch/types/hris/create_company_benefits_response.py
+++ b/src/finch/types/hris/create_company_benefits_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from ..._models import BaseModel
diff --git a/src/finch/types/hris/directory_list_individuals_params.py b/src/finch/types/hris/directory_list_individuals_params.py
index de07f63f..b70a073e 100644
--- a/src/finch/types/hris/directory_list_individuals_params.py
+++ b/src/finch/types/hris/directory_list_individuals_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/directory_list_params.py b/src/finch/types/hris/directory_list_params.py
index 83741e8b..f6aceee4 100644
--- a/src/finch/types/hris/directory_list_params.py
+++ b/src/finch/types/hris/directory_list_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/employment_data.py b/src/finch/types/hris/employment_data.py
index bec65992..57a19763 100644
--- a/src/finch/types/hris/employment_data.py
+++ b/src/finch/types/hris/employment_data.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/employment_data_response.py b/src/finch/types/hris/employment_data_response.py
index 24fd1b9c..605e4473 100644
--- a/src/finch/types/hris/employment_data_response.py
+++ b/src/finch/types/hris/employment_data_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/hris/employment_retrieve_many_params.py b/src/finch/types/hris/employment_retrieve_many_params.py
index 61cb2c21..0aeccf6c 100644
--- a/src/finch/types/hris/employment_retrieve_many_params.py
+++ b/src/finch/types/hris/employment_retrieve_many_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/individual.py b/src/finch/types/hris/individual.py
index 607ae581..cc077e34 100644
--- a/src/finch/types/hris/individual.py
+++ b/src/finch/types/hris/individual.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/individual_in_directory.py b/src/finch/types/hris/individual_in_directory.py
index 30e113a9..c29f34e1 100644
--- a/src/finch/types/hris/individual_in_directory.py
+++ b/src/finch/types/hris/individual_in_directory.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/hris/individual_response.py b/src/finch/types/hris/individual_response.py
index c1f00c2c..e9c80a47 100644
--- a/src/finch/types/hris/individual_response.py
+++ b/src/finch/types/hris/individual_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/hris/individual_retrieve_many_params.py b/src/finch/types/hris/individual_retrieve_many_params.py
index 7ec09d6a..33a0480a 100644
--- a/src/finch/types/hris/individual_retrieve_many_params.py
+++ b/src/finch/types/hris/individual_retrieve_many_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/pay_statement.py b/src/finch/types/hris/pay_statement.py
index 3d25a99c..dc3b1aba 100644
--- a/src/finch/types/hris/pay_statement.py
+++ b/src/finch/types/hris/pay_statement.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/pay_statement_response.py b/src/finch/types/hris/pay_statement_response.py
index 6545d2d3..35c33990 100644
--- a/src/finch/types/hris/pay_statement_response.py
+++ b/src/finch/types/hris/pay_statement_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/hris/pay_statement_response_body.py b/src/finch/types/hris/pay_statement_response_body.py
index c7563aac..004894e9 100644
--- a/src/finch/types/hris/pay_statement_response_body.py
+++ b/src/finch/types/hris/pay_statement_response_body.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
diff --git a/src/finch/types/hris/pay_statement_retrieve_many_params.py b/src/finch/types/hris/pay_statement_retrieve_many_params.py
index 686a7681..7a08009c 100644
--- a/src/finch/types/hris/pay_statement_retrieve_many_params.py
+++ b/src/finch/types/hris/pay_statement_retrieve_many_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/payment.py b/src/finch/types/hris/payment.py
index ebc8778b..a770d629 100644
--- a/src/finch/types/hris/payment.py
+++ b/src/finch/types/hris/payment.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
diff --git a/src/finch/types/hris/payment_list_params.py b/src/finch/types/hris/payment_list_params.py
index d3e69a9b..5b0cd004 100644
--- a/src/finch/types/hris/payment_list_params.py
+++ b/src/finch/types/hris/payment_list_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/hris/support_per_benefit_type.py b/src/finch/types/hris/support_per_benefit_type.py
index 2ce0dcee..62c5c15d 100644
--- a/src/finch/types/hris/support_per_benefit_type.py
+++ b/src/finch/types/hris/support_per_benefit_type.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/hris/supported_benefit.py b/src/finch/types/hris/supported_benefit.py
index d99bfae2..68613a5b 100644
--- a/src/finch/types/hris/supported_benefit.py
+++ b/src/finch/types/hris/supported_benefit.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/hris/update_company_benefit_response.py b/src/finch/types/hris/update_company_benefit_response.py
index 4cd064e4..29faf7b4 100644
--- a/src/finch/types/hris/update_company_benefit_response.py
+++ b/src/finch/types/hris/update_company_benefit_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from ..._models import BaseModel
diff --git a/src/finch/types/income.py b/src/finch/types/income.py
index 211d4864..d01ba0e9 100644
--- a/src/finch/types/income.py
+++ b/src/finch/types/income.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/income_param.py b/src/finch/types/income_param.py
index 5c378edd..4348d5be 100644
--- a/src/finch/types/income_param.py
+++ b/src/finch/types/income_param.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/individual_event.py b/src/finch/types/individual_event.py
index 0d51c89b..fb1ff8ec 100644
--- a/src/finch/types/individual_event.py
+++ b/src/finch/types/individual_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/introspection.py b/src/finch/types/introspection.py
index e7a41f2e..199dbd65 100644
--- a/src/finch/types/introspection.py
+++ b/src/finch/types/introspection.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/job_completion_event.py b/src/finch/types/job_completion_event.py
index 3f77efb0..db92dfac 100644
--- a/src/finch/types/job_completion_event.py
+++ b/src/finch/types/job_completion_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/jobs/__init__.py b/src/finch/types/jobs/__init__.py
index b0470846..b5eaa10b 100644
--- a/src/finch/types/jobs/__init__.py
+++ b/src/finch/types/jobs/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/jobs/automated_async_job.py b/src/finch/types/jobs/automated_async_job.py
index b09ae9d3..e9d75d8e 100644
--- a/src/finch/types/jobs/automated_async_job.py
+++ b/src/finch/types/jobs/automated_async_job.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from datetime import datetime
diff --git a/src/finch/types/jobs/automated_create_params.py b/src/finch/types/jobs/automated_create_params.py
index ea39170f..d00c77ee 100644
--- a/src/finch/types/jobs/automated_create_params.py
+++ b/src/finch/types/jobs/automated_create_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/jobs/automated_create_response.py b/src/finch/types/jobs/automated_create_response.py
index 1341d52b..9d53fb1c 100644
--- a/src/finch/types/jobs/automated_create_response.py
+++ b/src/finch/types/jobs/automated_create_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from ..._models import BaseModel
diff --git a/src/finch/types/jobs/automated_list_params.py b/src/finch/types/jobs/automated_list_params.py
index 4c24874f..21032e2c 100644
--- a/src/finch/types/jobs/automated_list_params.py
+++ b/src/finch/types/jobs/automated_list_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/jobs/manual_async_job.py b/src/finch/types/jobs/manual_async_job.py
index fdfbf153..56a82f4c 100644
--- a/src/finch/types/jobs/manual_async_job.py
+++ b/src/finch/types/jobs/manual_async_job.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/location.py b/src/finch/types/location.py
index dfde541e..fd0d0fab 100644
--- a/src/finch/types/location.py
+++ b/src/finch/types/location.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/location_param.py b/src/finch/types/location_param.py
index 11f4e33e..3bbcab82 100644
--- a/src/finch/types/location_param.py
+++ b/src/finch/types/location_param.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/money.py b/src/finch/types/money.py
index 424c5447..21ebb963 100644
--- a/src/finch/types/money.py
+++ b/src/finch/types/money.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/money_param.py b/src/finch/types/money_param.py
index 6d86df6c..180e8687 100644
--- a/src/finch/types/money_param.py
+++ b/src/finch/types/money_param.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/pay_statement_event.py b/src/finch/types/pay_statement_event.py
index b748e459..950f22fa 100644
--- a/src/finch/types/pay_statement_event.py
+++ b/src/finch/types/pay_statement_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/payment_event.py b/src/finch/types/payment_event.py
index dab1cebd..c4a101dd 100644
--- a/src/finch/types/payment_event.py
+++ b/src/finch/types/payment_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
from typing_extensions import Literal
diff --git a/src/finch/types/provider.py b/src/finch/types/provider.py
index 87d346ee..231a3354 100644
--- a/src/finch/types/provider.py
+++ b/src/finch/types/provider.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/request_forwarding_forward_params.py b/src/finch/types/request_forwarding_forward_params.py
index 19fe0062..76f06fed 100644
--- a/src/finch/types/request_forwarding_forward_params.py
+++ b/src/finch/types/request_forwarding_forward_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/request_forwarding_forward_response.py b/src/finch/types/request_forwarding_forward_response.py
index 71ab19a0..5b279d94 100644
--- a/src/finch/types/request_forwarding_forward_response.py
+++ b/src/finch/types/request_forwarding_forward_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/sandbox/__init__.py b/src/finch/types/sandbox/__init__.py
index 7a4d41fa..b0036a66 100644
--- a/src/finch/types/sandbox/__init__.py
+++ b/src/finch/types/sandbox/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/company_update_params.py b/src/finch/types/sandbox/company_update_params.py
index 5800d428..542a8b53 100644
--- a/src/finch/types/sandbox/company_update_params.py
+++ b/src/finch/types/sandbox/company_update_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/company_update_response.py b/src/finch/types/sandbox/company_update_response.py
index e5a4d2d6..8f0eb852 100644
--- a/src/finch/types/sandbox/company_update_response.py
+++ b/src/finch/types/sandbox/company_update_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/sandbox/connection_create_params.py b/src/finch/types/sandbox/connection_create_params.py
index d6c29927..e7e7ce05 100644
--- a/src/finch/types/sandbox/connection_create_params.py
+++ b/src/finch/types/sandbox/connection_create_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/connection_create_response.py b/src/finch/types/sandbox/connection_create_response.py
index fed64a63..26ff6764 100644
--- a/src/finch/types/sandbox/connection_create_response.py
+++ b/src/finch/types/sandbox/connection_create_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List
from typing_extensions import Literal
diff --git a/src/finch/types/sandbox/connections/__init__.py b/src/finch/types/sandbox/connections/__init__.py
index 7d68eabb..31dda963 100644
--- a/src/finch/types/sandbox/connections/__init__.py
+++ b/src/finch/types/sandbox/connections/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/connections/account_create_params.py b/src/finch/types/sandbox/connections/account_create_params.py
index 9dff294e..233e79d0 100644
--- a/src/finch/types/sandbox/connections/account_create_params.py
+++ b/src/finch/types/sandbox/connections/account_create_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/connections/account_create_response.py b/src/finch/types/sandbox/connections/account_create_response.py
index d1d32ad7..8c3467eb 100644
--- a/src/finch/types/sandbox/connections/account_create_response.py
+++ b/src/finch/types/sandbox/connections/account_create_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List
from typing_extensions import Literal
diff --git a/src/finch/types/sandbox/connections/account_update_params.py b/src/finch/types/sandbox/connections/account_update_params.py
index b2b8874d..66988111 100644
--- a/src/finch/types/sandbox/connections/account_update_params.py
+++ b/src/finch/types/sandbox/connections/account_update_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/connections/account_update_response.py b/src/finch/types/sandbox/connections/account_update_response.py
index 2fe7507d..ab4d3465 100644
--- a/src/finch/types/sandbox/connections/account_update_response.py
+++ b/src/finch/types/sandbox/connections/account_update_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List
from typing_extensions import Literal
diff --git a/src/finch/types/sandbox/directory_create_params.py b/src/finch/types/sandbox/directory_create_params.py
index 78647fb4..bf42ddd6 100644
--- a/src/finch/types/sandbox/directory_create_params.py
+++ b/src/finch/types/sandbox/directory_create_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/directory_create_response.py b/src/finch/types/sandbox/directory_create_response.py
index 6a0a4025..1d639939 100644
--- a/src/finch/types/sandbox/directory_create_response.py
+++ b/src/finch/types/sandbox/directory_create_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List
diff --git a/src/finch/types/sandbox/employment_update_params.py b/src/finch/types/sandbox/employment_update_params.py
index 8e4cc877..fa0bdbe7 100644
--- a/src/finch/types/sandbox/employment_update_params.py
+++ b/src/finch/types/sandbox/employment_update_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/employment_update_response.py b/src/finch/types/sandbox/employment_update_response.py
index 796aa25d..317cd03c 100644
--- a/src/finch/types/sandbox/employment_update_response.py
+++ b/src/finch/types/sandbox/employment_update_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/sandbox/individual_update_params.py b/src/finch/types/sandbox/individual_update_params.py
index cdae4cc2..a99a8675 100644
--- a/src/finch/types/sandbox/individual_update_params.py
+++ b/src/finch/types/sandbox/individual_update_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/individual_update_response.py b/src/finch/types/sandbox/individual_update_response.py
index 4db655e1..bb44a9a3 100644
--- a/src/finch/types/sandbox/individual_update_response.py
+++ b/src/finch/types/sandbox/individual_update_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
from typing_extensions import Literal
diff --git a/src/finch/types/sandbox/job_create_params.py b/src/finch/types/sandbox/job_create_params.py
index a3a89770..3fb3ced4 100644
--- a/src/finch/types/sandbox/job_create_params.py
+++ b/src/finch/types/sandbox/job_create_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/job_create_response.py b/src/finch/types/sandbox/job_create_response.py
index 0832ef7f..0c085dfc 100644
--- a/src/finch/types/sandbox/job_create_response.py
+++ b/src/finch/types/sandbox/job_create_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from ..._models import BaseModel
diff --git a/src/finch/types/sandbox/jobs/__init__.py b/src/finch/types/sandbox/jobs/__init__.py
index cec01f2e..7082c874 100644
--- a/src/finch/types/sandbox/jobs/__init__.py
+++ b/src/finch/types/sandbox/jobs/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/jobs/configuration_retrieve_response.py b/src/finch/types/sandbox/jobs/configuration_retrieve_response.py
index e46121ab..33fef2be 100644
--- a/src/finch/types/sandbox/jobs/configuration_retrieve_response.py
+++ b/src/finch/types/sandbox/jobs/configuration_retrieve_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List
diff --git a/src/finch/types/sandbox/jobs/configuration_update_params.py b/src/finch/types/sandbox/jobs/configuration_update_params.py
index 5a4955e6..dce75013 100644
--- a/src/finch/types/sandbox/jobs/configuration_update_params.py
+++ b/src/finch/types/sandbox/jobs/configuration_update_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/jobs/sandbox_job_configuration.py b/src/finch/types/sandbox/jobs/sandbox_job_configuration.py
index ff1be519..8d1089e7 100644
--- a/src/finch/types/sandbox/jobs/sandbox_job_configuration.py
+++ b/src/finch/types/sandbox/jobs/sandbox_job_configuration.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing_extensions import Literal
diff --git a/src/finch/types/sandbox/payment_create_params.py b/src/finch/types/sandbox/payment_create_params.py
index f1568001..e3068be9 100644
--- a/src/finch/types/sandbox/payment_create_params.py
+++ b/src/finch/types/sandbox/payment_create_params.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/sandbox/payment_create_response.py b/src/finch/types/sandbox/payment_create_response.py
index 4e3bcf57..17cdaa8a 100644
--- a/src/finch/types/sandbox/payment_create_response.py
+++ b/src/finch/types/sandbox/payment_create_response.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from ..._models import BaseModel
diff --git a/src/finch/types/shared/__init__.py b/src/finch/types/shared/__init__.py
index 47337493..587d2f52 100644
--- a/src/finch/types/shared/__init__.py
+++ b/src/finch/types/shared/__init__.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .paging import Paging as Paging
from .operation_support import OperationSupport as OperationSupport
diff --git a/src/finch/types/shared/connection_status_type.py b/src/finch/types/shared/connection_status_type.py
index f493e50b..9021c0b7 100644
--- a/src/finch/types/shared/connection_status_type.py
+++ b/src/finch/types/shared/connection_status_type.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing_extensions import Literal
diff --git a/src/finch/types/shared/operation_support.py b/src/finch/types/shared/operation_support.py
index 9ae5ebf6..10bda0ab 100644
--- a/src/finch/types/shared/operation_support.py
+++ b/src/finch/types/shared/operation_support.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing_extensions import Literal
diff --git a/src/finch/types/shared/operation_support_matrix.py b/src/finch/types/shared/operation_support_matrix.py
index a054391f..bfd21bb4 100644
--- a/src/finch/types/shared/operation_support_matrix.py
+++ b/src/finch/types/shared/operation_support_matrix.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/shared/paging.py b/src/finch/types/shared/paging.py
index 726478fa..418c49b6 100644
--- a/src/finch/types/shared/paging.py
+++ b/src/finch/types/shared/paging.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
diff --git a/src/finch/types/shared_params/__init__.py b/src/finch/types/shared_params/__init__.py
index d47d37df..3b817791 100644
--- a/src/finch/types/shared_params/__init__.py
+++ b/src/finch/types/shared_params/__init__.py
@@ -1,3 +1,3 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from .connection_status_type import ConnectionStatusType as ConnectionStatusType
diff --git a/src/finch/types/shared_params/connection_status_type.py b/src/finch/types/shared_params/connection_status_type.py
index 26562dda..d7caa1cf 100644
--- a/src/finch/types/shared_params/connection_status_type.py
+++ b/src/finch/types/shared_params/connection_status_type.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/src/finch/types/webhook_event.py b/src/finch/types/webhook_event.py
index ded9cf4e..8d3788c2 100644
--- a/src/finch/types/webhook_event.py
+++ b/src/finch/types/webhook_event.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Union
diff --git a/tests/__init__.py b/tests/__init__.py
index 1016754e..fd8019a9 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1 +1 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/__init__.py b/tests/api_resources/__init__.py
index 1016754e..fd8019a9 100644
--- a/tests/api_resources/__init__.py
+++ b/tests/api_resources/__init__.py
@@ -1 +1 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/hris/__init__.py b/tests/api_resources/hris/__init__.py
index 1016754e..fd8019a9 100644
--- a/tests/api_resources/hris/__init__.py
+++ b/tests/api_resources/hris/__init__.py
@@ -1 +1 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/hris/benefits/__init__.py b/tests/api_resources/hris/benefits/__init__.py
index 1016754e..fd8019a9 100644
--- a/tests/api_resources/hris/benefits/__init__.py
+++ b/tests/api_resources/hris/benefits/__init__.py
@@ -1 +1 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/hris/benefits/test_individuals.py b/tests/api_resources/hris/benefits/test_individuals.py
index 00e182a5..9defbc96 100644
--- a/tests/api_resources/hris/benefits/test_individuals.py
+++ b/tests/api_resources/hris/benefits/test_individuals.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/hris/test_benefits.py b/tests/api_resources/hris/test_benefits.py
index 8d7d6510..ea02d4ac 100644
--- a/tests/api_resources/hris/test_benefits.py
+++ b/tests/api_resources/hris/test_benefits.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/hris/test_company.py b/tests/api_resources/hris/test_company.py
index d9f50bb0..ea4052f9 100644
--- a/tests/api_resources/hris/test_company.py
+++ b/tests/api_resources/hris/test_company.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/hris/test_directory.py b/tests/api_resources/hris/test_directory.py
index 92308518..5822d710 100644
--- a/tests/api_resources/hris/test_directory.py
+++ b/tests/api_resources/hris/test_directory.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/hris/test_employments.py b/tests/api_resources/hris/test_employments.py
index d6d53313..d228f309 100644
--- a/tests/api_resources/hris/test_employments.py
+++ b/tests/api_resources/hris/test_employments.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/hris/test_individuals.py b/tests/api_resources/hris/test_individuals.py
index 12b244a0..f34d10fb 100644
--- a/tests/api_resources/hris/test_individuals.py
+++ b/tests/api_resources/hris/test_individuals.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/hris/test_pay_statements.py b/tests/api_resources/hris/test_pay_statements.py
index 8b96e656..b52cc2b7 100644
--- a/tests/api_resources/hris/test_pay_statements.py
+++ b/tests/api_resources/hris/test_pay_statements.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/hris/test_payments.py b/tests/api_resources/hris/test_payments.py
index 022a0c30..70b183ea 100644
--- a/tests/api_resources/hris/test_payments.py
+++ b/tests/api_resources/hris/test_payments.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/jobs/__init__.py b/tests/api_resources/jobs/__init__.py
index 1016754e..fd8019a9 100644
--- a/tests/api_resources/jobs/__init__.py
+++ b/tests/api_resources/jobs/__init__.py
@@ -1 +1 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/jobs/test_automated.py b/tests/api_resources/jobs/test_automated.py
index c683780c..5cf5644a 100644
--- a/tests/api_resources/jobs/test_automated.py
+++ b/tests/api_resources/jobs/test_automated.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/jobs/test_manual.py b/tests/api_resources/jobs/test_manual.py
index f8ab6edf..ec6d528a 100644
--- a/tests/api_resources/jobs/test_manual.py
+++ b/tests/api_resources/jobs/test_manual.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/__init__.py b/tests/api_resources/sandbox/__init__.py
index 1016754e..fd8019a9 100644
--- a/tests/api_resources/sandbox/__init__.py
+++ b/tests/api_resources/sandbox/__init__.py
@@ -1 +1 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/sandbox/connections/__init__.py b/tests/api_resources/sandbox/connections/__init__.py
index 1016754e..fd8019a9 100644
--- a/tests/api_resources/sandbox/connections/__init__.py
+++ b/tests/api_resources/sandbox/connections/__init__.py
@@ -1 +1 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/sandbox/connections/test_accounts.py b/tests/api_resources/sandbox/connections/test_accounts.py
index 5dedf19d..82058694 100644
--- a/tests/api_resources/sandbox/connections/test_accounts.py
+++ b/tests/api_resources/sandbox/connections/test_accounts.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/jobs/__init__.py b/tests/api_resources/sandbox/jobs/__init__.py
index 1016754e..fd8019a9 100644
--- a/tests/api_resources/sandbox/jobs/__init__.py
+++ b/tests/api_resources/sandbox/jobs/__init__.py
@@ -1 +1 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/sandbox/jobs/test_configuration.py b/tests/api_resources/sandbox/jobs/test_configuration.py
index 17d4f21b..b7d8ac2c 100644
--- a/tests/api_resources/sandbox/jobs/test_configuration.py
+++ b/tests/api_resources/sandbox/jobs/test_configuration.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/test_company.py b/tests/api_resources/sandbox/test_company.py
index c542d166..4104eb8a 100644
--- a/tests/api_resources/sandbox/test_company.py
+++ b/tests/api_resources/sandbox/test_company.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/test_connections.py b/tests/api_resources/sandbox/test_connections.py
index c3d19e06..2cbb0fe0 100644
--- a/tests/api_resources/sandbox/test_connections.py
+++ b/tests/api_resources/sandbox/test_connections.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/test_directory.py b/tests/api_resources/sandbox/test_directory.py
index c73edba0..a42d4fcb 100644
--- a/tests/api_resources/sandbox/test_directory.py
+++ b/tests/api_resources/sandbox/test_directory.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/test_employment.py b/tests/api_resources/sandbox/test_employment.py
index f055e7ad..7183dac5 100644
--- a/tests/api_resources/sandbox/test_employment.py
+++ b/tests/api_resources/sandbox/test_employment.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/test_individual.py b/tests/api_resources/sandbox/test_individual.py
index 7e40c602..5d8f0683 100644
--- a/tests/api_resources/sandbox/test_individual.py
+++ b/tests/api_resources/sandbox/test_individual.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/test_jobs.py b/tests/api_resources/sandbox/test_jobs.py
index f0db9c28..fd990987 100644
--- a/tests/api_resources/sandbox/test_jobs.py
+++ b/tests/api_resources/sandbox/test_jobs.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/sandbox/test_payment.py b/tests/api_resources/sandbox/test_payment.py
index 86be4bbb..9b0c803a 100644
--- a/tests/api_resources/sandbox/test_payment.py
+++ b/tests/api_resources/sandbox/test_payment.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/test_access_tokens.py b/tests/api_resources/test_access_tokens.py
index e909b979..3dcbe2e3 100644
--- a/tests/api_resources/test_access_tokens.py
+++ b/tests/api_resources/test_access_tokens.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/test_account.py b/tests/api_resources/test_account.py
index 7dedf857..2464a527 100644
--- a/tests/api_resources/test_account.py
+++ b/tests/api_resources/test_account.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/test_providers.py b/tests/api_resources/test_providers.py
index a9ef8c2b..380fdf9c 100644
--- a/tests/api_resources/test_providers.py
+++ b/tests/api_resources/test_providers.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/test_request_forwarding.py b/tests/api_resources/test_request_forwarding.py
index de68152d..ea0c6319 100644
--- a/tests/api_resources/test_request_forwarding.py
+++ b/tests/api_resources/test_request_forwarding.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/test_top_level.py b/tests/api_resources/test_top_level.py
index c0752165..e1c15ec0 100644
--- a/tests/api_resources/test_top_level.py
+++ b/tests/api_resources/test_top_level.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/api_resources/test_webhooks.py b/tests/api_resources/test_webhooks.py
index edcd45f8..72b7d6af 100644
--- a/tests/api_resources/test_webhooks.py
+++ b/tests/api_resources/test_webhooks.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
diff --git a/tests/test_client.py b/tests/test_client.py
index dac0d6c1..64706426 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -1,4 +1,4 @@
-# File generated from our OpenAPI spec by Stainless.
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
From 3fdcf2e89f9ba3ef341e0402d3cfd528ad568af5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 20 Mar 2024 14:24:32 +0000
Subject: [PATCH 04/13] chore(internal): loosen input type for util function
(#328)
---
src/finch/_models.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/finch/_models.py b/src/finch/_models.py
index 16697353..35a23a95 100644
--- a/src/finch/_models.py
+++ b/src/finch/_models.py
@@ -290,11 +290,15 @@ def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericMo
return issubclass(origin, BaseModel) or issubclass(origin, GenericModel)
-def construct_type(*, value: object, type_: type) -> object:
+def construct_type(*, value: object, type_: object) -> object:
"""Loose coercion to the expected type with construction of nested values.
If the given value does not match the expected type then it is returned as-is.
"""
+ # 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_)
+
# unwrap `Annotated[T, ...]` -> `T`
if is_annotated_type(type_):
meta = get_args(type_)[1:]
From 55bf27d677d81c1272b148ec37fdac8b5dd4fc68 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 21 Mar 2024 03:26:02 +0000
Subject: [PATCH 05/13] docs(readme): document how to make undocumented
requests (#329)
---
README.md | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/README.md b/README.md
index 20b3a152..8e807ac0 100644
--- a/README.md
+++ b/README.md
@@ -336,6 +336,41 @@ with client.hris.directory.with_streaming_response.list() as response:
The context manager is required so that the response will reliably be closed.
+### Making custom/undocumented requests
+
+This library is typed for convenient access the documented API.
+
+If you need to access undocumented endpoints, params, or response properties, the library can still be used.
+
+#### Undocumented endpoints
+
+To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other
+http verbs. Options on the client will be respected (such as retries) will be respected when making this
+request.
+
+```py
+import httpx
+
+response = client.post(
+ "/foo",
+ cast_to=httpx.Response,
+ body={"my_param": True},
+)
+
+print(response.headers.get("x-foo"))
+```
+
+#### Undocumented params
+
+If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request
+options.
+
+#### Undocumented properties
+
+To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You
+can also get all the extra fields on the Pydantic model as a dict with
+[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).
+
### Configuring the HTTP client
You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:
From 6b8829f4999a3e243d63f45126000b5ad2a6b9ef Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 21 Mar 2024 17:36:25 +0000
Subject: [PATCH 06/13] chore(internal): formatting change (#330)
---
pyproject.toml | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyproject.toml b/pyproject.toml
index a130b590..c6a548ec 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -130,6 +130,7 @@ reportImplicitOverride = true
reportImportCycles = false
reportPrivateUsage = false
+
[tool.ruff]
line-length = 120
output-format = "grouped"
From 15c71d5bc77fda5bb4b2f7aec53c75f49987ae3b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 22 Mar 2024 10:31:39 +0000
Subject: [PATCH 07/13] docs(contributing): fix typo (#331)
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c6bf27ef..98563944 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -121,5 +121,5 @@ You can release to package managers by using [the `Publish PyPI` GitHub action](
### Publish manually
-If you need to manually release a package, you can run the `bin/publish-pypi` script with an `PYPI_TOKEN` set on
+If you need to manually release a package, you can run the `bin/publish-pypi` script with a `PYPI_TOKEN` set on
the environment.
From da0031cd66a123f339a65ad63a731e97ad65383f Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 25 Mar 2024 10:32:10 +0000
Subject: [PATCH 08/13] fix: revert regression with 3.7 support (#332)
---
src/finch/_models.py | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/finch/_models.py b/src/finch/_models.py
index 35a23a95..77c755b1 100644
--- a/src/finch/_models.py
+++ b/src/finch/_models.py
@@ -538,12 +538,14 @@ class GenericModel(BaseGenericModel, BaseModel):
if PYDANTIC_V2:
+ from pydantic import TypeAdapter as _TypeAdapter
+
+ _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter))
+
if TYPE_CHECKING:
from pydantic import TypeAdapter
else:
- from pydantic import TypeAdapter as _TypeAdapter
-
- TypeAdapter = lru_cache(_TypeAdapter)
+ TypeAdapter = _CachedTypeAdapter
def _validate_non_model_type(*, type_: type[_T], value: object) -> _T:
return TypeAdapter(type_).validate_python(value)
From 5e42474c6a00a6ec3e8a11db753ffbecb6e9a1e3 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 27 Mar 2024 17:04:03 +0000
Subject: [PATCH 09/13] chore: temporary commit (#333)
---
README.md | 23 ---
api.md | 12 --
src/finch/_client.py | 132 ---------------
src/finch/resources/__init__.py | 3 -
src/finch/resources/access_tokens.py | 39 +----
src/finch/resources/webhooks.py | 221 --------------------------
tests/api_resources/test_top_level.py | 17 --
tests/api_resources/test_webhooks.py | 214 -------------------------
8 files changed, 7 insertions(+), 654 deletions(-)
delete mode 100644 src/finch/resources/webhooks.py
delete mode 100644 tests/api_resources/test_top_level.py
delete mode 100644 tests/api_resources/test_webhooks.py
diff --git a/README.md b/README.md
index 8e807ac0..191c1ee5 100644
--- a/README.md
+++ b/README.md
@@ -142,29 +142,6 @@ page = client.hris.directory.list()
print(page.page)
```
-## Webhook Verification
-
-We provide helper methods for verifying that a webhook request came from Finch, and not a malicious third party.
-
-You can use `finch.webhooks.verify_signature(body: string, headers, secret?) -> None` or `finch.webhooks.unwrap(body: string, headers, secret?) -> Payload`,
-both of which will raise an error if the signature is invalid.
-
-Note that the "body" parameter must be the raw JSON string sent from the server (do not parse it first).
-The `.unwrap()` method can parse this JSON for you into a `Payload` object.
-
-For example, in [FastAPI](https://fastapi.tiangolo.com/):
-
-```py
-@app.post('/my-webhook-handler')
-async def handler(request: Request):
- body = await request.body()
- secret = os.environ['FINCH_WEBHOOK_SECRET'] # env var used by default; explicit here.
- payload = client.webhooks.unwrap(body, request.headers, secret)
- print(payload)
-
- return {'ok': True}
-```
-
## Handling errors
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `finch.APIConnectionError` is raised.
diff --git a/api.md b/api.md
index 80dfe151..5ca9c362 100644
--- a/api.md
+++ b/api.md
@@ -4,13 +4,6 @@
from finch.types import ConnectionStatusType, OperationSupport, OperationSupportMatrix, Paging
```
-# Finch
-
-Methods:
-
-- client.get_auth_url(\*args) -> str
-- client.with_access_token(\*args) -> Self
-
# AccessTokens
Types:
@@ -195,11 +188,6 @@ from finch.types import (
)
```
-Methods:
-
-- client.webhooks.unwrap(\*args) -> WebhookEvent
-- client.webhooks.verify_signature(\*args) -> None
-
# RequestForwarding
Types:
diff --git a/src/finch/_client.py b/src/finch/_client.py
index cddb281d..9afd1c69 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -56,7 +56,6 @@ class Finch(SyncAPIClient):
hris: resources.HRIS
providers: resources.Providers
account: resources.Account
- webhooks: resources.Webhooks
request_forwarding: resources.RequestForwarding
jobs: resources.Jobs
sandbox: resources.Sandbox
@@ -157,7 +156,6 @@ def __init__(
self.hris = resources.HRIS(self)
self.providers = resources.Providers(self)
self.account = resources.Account(self)
- self.webhooks = resources.Webhooks(self)
self.request_forwarding = resources.RequestForwarding(self)
self.jobs = resources.Jobs(self)
self.sandbox = resources.Sandbox(self)
@@ -301,70 +299,6 @@ def copy(
# client.with_options(timeout=10).foo.create(...)
with_options = copy
- def get_access_token(
- self,
- code: str,
- *,
- redirect_uri: str | None = None,
- ) -> str:
- """DEPRECATED: use client.access_tokens.create instead."""
- if self.client_id is None:
- raise ValueError("Expected client_id to be set in order to call get_access_token")
-
- if self.client_secret is None:
- raise ValueError("Expected client_secret to be set in order to call get_access_token")
-
- response = self.post(
- "/auth/token",
- body={
- "client_id": self.client_id,
- "client_secret": self.client_secret,
- "code": code,
- "redirect_uri": redirect_uri,
- },
- options={"headers": {"Authorization": Omit()}},
- cast_to=httpx.Response,
- )
- data = response.json()
- return str(data["access_token"])
-
- def get_auth_url(
- self,
- *,
- products: str,
- redirect_uri: str,
- sandbox: bool,
- ) -> str:
- """
- Returns the authorization url which can be visited in order to obtain an
- authorization code from Finch. The authorization code can then be exchanged for
- an access token for the Finch api by calling get_access_token().
- """
- if self.client_id is None:
- raise ValueError("Expected the client_id to be set in order to call get_auth_url")
-
- return str(
- httpx.URL(
- "https://connect.tryfinch.com/authorize",
- params={
- "client_id": self.client_id,
- "products": products,
- "redirect_uri": redirect_uri,
- "sandbox": sandbox,
- },
- )
- )
-
- def with_access_token(
- self,
- access_token: str,
- ) -> Self:
- """
- Returns a copy of the current Finch client with the given access token for
- authentication.
- """
- return self.with_options(access_token=access_token)
-
@override
def _make_status_error(
self,
@@ -404,7 +338,6 @@ class AsyncFinch(AsyncAPIClient):
hris: resources.AsyncHRIS
providers: resources.AsyncProviders
account: resources.AsyncAccount
- webhooks: resources.AsyncWebhooks
request_forwarding: resources.AsyncRequestForwarding
jobs: resources.AsyncJobs
sandbox: resources.AsyncSandbox
@@ -505,7 +438,6 @@ def __init__(
self.hris = resources.AsyncHRIS(self)
self.providers = resources.AsyncProviders(self)
self.account = resources.AsyncAccount(self)
- self.webhooks = resources.AsyncWebhooks(self)
self.request_forwarding = resources.AsyncRequestForwarding(self)
self.jobs = resources.AsyncJobs(self)
self.sandbox = resources.AsyncSandbox(self)
@@ -649,70 +581,6 @@ def copy(
# client.with_options(timeout=10).foo.create(...)
with_options = copy
- async def get_access_token(
- self,
- code: str,
- *,
- redirect_uri: str | None = None,
- ) -> str:
- """DEPRECATED: use client.access_tokens.create instead."""
- if self.client_id is None:
- raise ValueError("Expected client_id to be set in order to call get_access_token")
-
- if self.client_secret is None:
- raise ValueError("Expected client_secret to be set in order to call get_access_token")
-
- response = await self.post(
- "/auth/token",
- body={
- "client_id": self.client_id,
- "client_secret": self.client_secret,
- "code": code,
- "redirect_uri": redirect_uri,
- },
- options={"headers": {"Authorization": Omit()}},
- cast_to=httpx.Response,
- )
- data = response.json()
- return str(data["access_token"])
-
- def get_auth_url(
- self,
- *,
- products: str,
- redirect_uri: str,
- sandbox: bool,
- ) -> str:
- """
- Returns the authorization url which can be visited in order to obtain an
- authorization code from Finch. The authorization code can then be exchanged for
- an access token for the Finch api by calling get_access_token().
- """
- if self.client_id is None:
- raise ValueError("Expected the client_id to be set in order to call get_auth_url")
-
- return str(
- httpx.URL(
- "https://connect.tryfinch.com/authorize",
- params={
- "client_id": self.client_id,
- "products": products,
- "redirect_uri": redirect_uri,
- "sandbox": sandbox,
- },
- )
- )
-
- def with_access_token(
- self,
- access_token: str,
- ) -> Self:
- """
- Returns a copy of the current Finch client with the given access token for
- authentication.
- """
- return self.with_options(access_token=access_token)
-
@override
def _make_status_error(
self,
diff --git a/src/finch/resources/__init__.py b/src/finch/resources/__init__.py
index d5f226e9..04bef46f 100644
--- a/src/finch/resources/__init__.py
+++ b/src/finch/resources/__init__.py
@@ -32,7 +32,6 @@
SandboxWithStreamingResponse,
AsyncSandboxWithStreamingResponse,
)
-from .webhooks import Webhooks, AsyncWebhooks
from .providers import (
Providers,
AsyncProviders,
@@ -83,8 +82,6 @@
"AsyncAccountWithRawResponse",
"AccountWithStreamingResponse",
"AsyncAccountWithStreamingResponse",
- "Webhooks",
- "AsyncWebhooks",
"RequestForwarding",
"AsyncRequestForwarding",
"RequestForwardingWithRawResponse",
diff --git a/src/finch/resources/access_tokens.py b/src/finch/resources/access_tokens.py
index 7e4fad17..8b5086d7 100644
--- a/src/finch/resources/access_tokens.py
+++ b/src/finch/resources/access_tokens.py
@@ -7,7 +7,10 @@
from .. import _legacy_response
from ..types import CreateAccessTokenResponse, access_token_create_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
-from .._utils import is_given, maybe_transform
+from .._utils import (
+ maybe_transform,
+ async_maybe_transform,
+)
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
@@ -53,27 +56,13 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not is_given(client_id):
- if self._client.client_id is None:
- raise ValueError(
- "client_id must be provided as an argument or with the FINCH_CLIENT_ID environment variable"
- )
- client_id = self._client.client_id
-
- if not is_given(client_secret):
- if self._client.client_secret is None:
- raise ValueError(
- "client_secret must be provided as an argument or with the FINCH_CLIENT_SECRET environment variable"
- )
- client_secret = self._client.client_secret
-
return self._post(
"/auth/token",
body=maybe_transform(
{
+ "code": code,
"client_id": client_id,
"client_secret": client_secret,
- "code": code,
"redirect_uri": redirect_uri,
},
access_token_create_params.AccessTokenCreateParams,
@@ -120,27 +109,13 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not is_given(client_id):
- if self._client.client_id is None:
- raise ValueError(
- "client_id must be provided as an argument or with the FINCH_CLIENT_ID environment variable"
- )
- client_id = self._client.client_id
-
- if not is_given(client_secret):
- if self._client.client_secret is None:
- raise ValueError(
- "client_secret must be provided as an argument or with the FINCH_CLIENT_SECRET environment variable"
- )
- client_secret = self._client.client_secret
-
return await self._post(
"/auth/token",
- body=maybe_transform(
+ body=await async_maybe_transform(
{
+ "code": code,
"client_id": client_id,
"client_secret": client_secret,
- "code": code,
"redirect_uri": redirect_uri,
},
access_token_create_params.AccessTokenCreateParams,
diff --git a/src/finch/resources/webhooks.py b/src/finch/resources/webhooks.py
deleted file mode 100644
index 0fe50944..00000000
--- a/src/finch/resources/webhooks.py
+++ /dev/null
@@ -1,221 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import hmac
-import json
-import math
-import base64
-import hashlib
-from typing import cast
-from datetime import datetime, timezone, timedelta
-
-from ..types import WebhookEvent
-from .._types import (
- HeadersLike,
-)
-from .._utils import (
- get_required_header,
-)
-from .._models import construct_type
-from .._resource import SyncAPIResource, AsyncAPIResource
-
-__all__ = ["Webhooks", "AsyncWebhooks"]
-
-
-class Webhooks(SyncAPIResource):
- def unwrap(
- self,
- payload: str | bytes,
- headers: HeadersLike,
- *,
- secret: str | None = None,
- ) -> WebhookEvent:
- """Validates that the given payload was sent by Finch and parses the payload."""
- self.verify_signature(payload=payload, headers=headers, secret=secret)
- return cast(
- WebhookEvent,
- construct_type(
- value=json.loads(payload),
- type_=WebhookEvent, # type: ignore[arg-type]
- ),
- )
-
- def verify_signature(
- self,
- payload: str | bytes,
- headers: HeadersLike,
- *,
- secret: str | None = None,
- ) -> None:
- """Validates whether or not the webhook payload was sent by Finch.
-
- An error will be raised if the webhook payload was not sent by Finch.
- """
- if secret is None:
- secret = self._client.webhook_secret
-
- if secret is None:
- raise ValueError(
- "The webhook secret must either be set using the env var, FINCH_WEBHOOK_SECRET, on the client class, Finch(webhook_secret='123'), or passed to this function"
- )
-
- try:
- parsedSecret = base64.b64decode(secret)
- except Exception as err:
- raise ValueError("Bad secret") from err
-
- msg_id = get_required_header(headers, "finch-event-id")
- msg_timestamp = get_required_header(headers, "finch-timestamp")
-
- # validate the timestamp
- webhook_tolerance = timedelta(minutes=5)
- now = datetime.now(tz=timezone.utc)
-
- try:
- timestamp = datetime.fromtimestamp(float(msg_timestamp), tz=timezone.utc)
- except Exception as err:
- raise ValueError("Invalid timestamp header: " + msg_timestamp + ". Could not convert to timestamp") from err
-
- # too old
- if timestamp < (now - webhook_tolerance):
- raise ValueError("Webhook timestamp is too old")
-
- # too new
- if timestamp > (now + webhook_tolerance):
- raise ValueError("Webhook timestamp is too new")
-
- # create the signature
- body = payload.decode("utf-8") if isinstance(payload, bytes) else payload
- if not isinstance(body, str): # pyright: ignore[reportUnnecessaryIsInstance]
- raise ValueError(
- "Webhook body should be a string of JSON (or bytes which can be decoded to a utf-8 string), not a parsed dictionary."
- )
-
- timestamp_str = str(math.floor(timestamp.replace(tzinfo=timezone.utc).timestamp()))
-
- to_sign = f"{msg_id}.{timestamp_str}.{body}".encode()
- expected_signature = hmac.new(parsedSecret, to_sign, hashlib.sha256).digest()
-
- msg_signature = get_required_header(headers, "finch-signature")
-
- # Signature header can contain multiple signatures delimited by spaces
- passed_sigs = msg_signature.split(" ")
-
- for versioned_sig in passed_sigs:
- values = versioned_sig.split(",")
- if len(values) != 2:
- # signature is not formatted like {version},{signature}
- continue
-
- (version, signature) = values
-
- # Only verify prefix v1
- if version != "v1":
- continue
-
- sig_bytes = base64.b64decode(signature)
- if hmac.compare_digest(expected_signature, sig_bytes):
- # valid!
- return None
-
- raise ValueError("None of the given webhook signatures match the expected signature")
-
-
-class AsyncWebhooks(AsyncAPIResource):
- def unwrap(
- self,
- payload: str | bytes,
- headers: HeadersLike,
- *,
- secret: str | None = None,
- ) -> WebhookEvent:
- """Validates that the given payload was sent by Finch and parses the payload."""
- self.verify_signature(payload=payload, headers=headers, secret=secret)
- return cast(
- WebhookEvent,
- construct_type(
- value=json.loads(payload),
- type_=WebhookEvent, # type: ignore[arg-type]
- ),
- )
-
- def verify_signature(
- self,
- payload: str | bytes,
- headers: HeadersLike,
- *,
- secret: str | None = None,
- ) -> None:
- """Validates whether or not the webhook payload was sent by Finch.
-
- An error will be raised if the webhook payload was not sent by Finch.
- """
- if secret is None:
- secret = self._client.webhook_secret
-
- if secret is None:
- raise ValueError(
- "The webhook secret must either be set using the env var, FINCH_WEBHOOK_SECRET, on the client class, Finch(webhook_secret='123'), or passed to this function"
- )
-
- try:
- parsedSecret = base64.b64decode(secret)
- except Exception as err:
- raise ValueError("Bad secret") from err
-
- msg_id = get_required_header(headers, "finch-event-id")
- msg_timestamp = get_required_header(headers, "finch-timestamp")
-
- # validate the timestamp
- webhook_tolerance = timedelta(minutes=5)
- now = datetime.now(tz=timezone.utc)
-
- try:
- timestamp = datetime.fromtimestamp(float(msg_timestamp), tz=timezone.utc)
- except Exception as err:
- raise ValueError("Invalid timestamp header: " + msg_timestamp + ". Could not convert to timestamp") from err
-
- # too old
- if timestamp < (now - webhook_tolerance):
- raise ValueError("Webhook timestamp is too old")
-
- # too new
- if timestamp > (now + webhook_tolerance):
- raise ValueError("Webhook timestamp is too new")
-
- # create the signature
- body = payload.decode("utf-8") if isinstance(payload, bytes) else payload
- if not isinstance(body, str): # pyright: ignore[reportUnnecessaryIsInstance]
- raise ValueError(
- "Webhook body should be a string of JSON (or bytes which can be decoded to a utf-8 string), not a parsed dictionary."
- )
-
- timestamp_str = str(math.floor(timestamp.replace(tzinfo=timezone.utc).timestamp()))
-
- to_sign = f"{msg_id}.{timestamp_str}.{body}".encode()
- expected_signature = hmac.new(parsedSecret, to_sign, hashlib.sha256).digest()
-
- msg_signature = get_required_header(headers, "finch-signature")
-
- # Signature header can contain multiple signatures delimited by spaces
- passed_sigs = msg_signature.split(" ")
-
- for versioned_sig in passed_sigs:
- values = versioned_sig.split(",")
- if len(values) != 2:
- # signature is not formatted like {version},{signature}
- continue
-
- (version, signature) = values
-
- # Only verify prefix v1
- if version != "v1":
- continue
-
- sig_bytes = base64.b64decode(signature)
- if hmac.compare_digest(expected_signature, sig_bytes):
- # valid!
- return None
-
- raise ValueError("None of the given webhook signatures match the expected signature")
diff --git a/tests/api_resources/test_top_level.py b/tests/api_resources/test_top_level.py
deleted file mode 100644
index e1c15ec0..00000000
--- a/tests/api_resources/test_top_level.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import os
-
-import pytest
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestTopLevel:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
-
-class TestAsyncTopLevel:
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
diff --git a/tests/api_resources/test_webhooks.py b/tests/api_resources/test_webhooks.py
deleted file mode 100644
index 72b7d6af..00000000
--- a/tests/api_resources/test_webhooks.py
+++ /dev/null
@@ -1,214 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import os
-import base64
-from typing import Any, cast
-from datetime import datetime, timezone, timedelta
-
-import pytest
-import time_machine
-from pydantic import BaseModel
-
-from finch import Finch, AsyncFinch
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestWebhooks:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- timestamp = "1676312382"
- fake_now = datetime.fromtimestamp(float(timestamp), tz=timezone.utc)
-
- payload = """{"company_id":"720be419-0293-4d32-a707-32179b0827ab"}"""
- signature = "m7y0TV2C+hlHxU42wCieApTSTaA8/047OAplBqxIV/s="
- headers = {
- "Finch-Event-Id": "msg_2Lh9KRb0pzN4LePd3XiA4v12Axj",
- "finch-timestamp": timestamp,
- "finch-signature": f"v1,{signature}",
- }
- secret = "5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH"
-
- @time_machine.travel(fake_now)
- def test_unwrap(self, client: Finch) -> None:
- payload = self.payload
- headers = self.headers
- secret = self.secret
-
- obj = client.webhooks.unwrap(payload, headers, secret=secret)
- assert isinstance(obj, BaseModel)
-
- @time_machine.travel(fake_now)
- def test_verify_signature(self, client: Finch) -> None:
- payload = self.payload
- headers = self.headers
- secret = self.secret
- signature = self.signature
- verify = client.webhooks.verify_signature
-
- assert verify(payload=payload, headers=headers, secret=secret) is None
-
- with pytest.raises(ValueError, match="Webhook timestamp is too old"):
- with time_machine.travel(self.fake_now + timedelta(minutes=6)):
- assert verify(payload=payload, headers=headers, secret=secret) is False
-
- with pytest.raises(ValueError, match="Webhook timestamp is too new"):
- with time_machine.travel(self.fake_now - timedelta(minutes=6)):
- assert verify(payload=payload, headers=headers, secret=secret) is False
-
- # wrong secret
- with pytest.raises(ValueError, match=r"Bad secret"):
- verify(payload=payload, headers=headers, secret="invalid secret")
-
- invalid_signature_message = "None of the given webhook signatures match the expected signature"
- with pytest.raises(ValueError, match=invalid_signature_message):
- verify(
- payload=payload,
- headers=headers,
- secret=base64.b64encode(b"foo").decode("utf-8"),
- )
-
- # multiple signatures
- invalid_signature = base64.b64encode(b"my_sig").decode("utf-8")
- assert (
- verify(
- payload=payload,
- headers={**headers, "finch-signature": f"v1,{invalid_signature} v1,{signature}"},
- secret=secret,
- )
- is None
- )
-
- # different signature version
- with pytest.raises(ValueError, match=invalid_signature_message):
- verify(
- payload=payload,
- headers={**headers, "finch-signature": f"v2,{signature}"},
- secret=secret,
- )
-
- assert (
- verify(
- payload=payload,
- headers={**headers, "finch-signature": f"v2,{signature} v1,{signature}"},
- secret=secret,
- )
- is None
- )
-
- # missing version
- with pytest.raises(ValueError, match=invalid_signature_message):
- verify(
- payload=payload,
- headers={**headers, "finch-signature": signature},
- secret=secret,
- )
-
- # non-string payload
- with pytest.raises(ValueError, match=r"Webhook body should be a string"):
- verify(
- payload=cast(Any, {"payload": payload}),
- headers=headers,
- secret=secret,
- )
-
-
-class TestAsyncWebhooks:
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
-
- timestamp = "1676312382"
- fake_now = datetime.fromtimestamp(float(timestamp), tz=timezone.utc)
-
- payload = """{"company_id":"720be419-0293-4d32-a707-32179b0827ab"}"""
- signature = "m7y0TV2C+hlHxU42wCieApTSTaA8/047OAplBqxIV/s="
- headers = {
- "Finch-Event-Id": "msg_2Lh9KRb0pzN4LePd3XiA4v12Axj",
- "finch-timestamp": timestamp,
- "finch-signature": f"v1,{signature}",
- }
- secret = "5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH"
-
- @time_machine.travel(fake_now)
- def test_unwrap(self, async_client: AsyncFinch) -> None:
- payload = self.payload
- headers = self.headers
- secret = self.secret
-
- obj = async_client.webhooks.unwrap(payload, headers, secret=secret)
- assert isinstance(obj, BaseModel)
-
- @time_machine.travel(fake_now)
- def test_verify_signature(self, async_client: AsyncFinch) -> None:
- payload = self.payload
- headers = self.headers
- secret = self.secret
- signature = self.signature
- verify = async_client.webhooks.verify_signature
-
- assert verify(payload=payload, headers=headers, secret=secret) is None
-
- with pytest.raises(ValueError, match="Webhook timestamp is too old"):
- with time_machine.travel(self.fake_now + timedelta(minutes=6)):
- assert verify(payload=payload, headers=headers, secret=secret) is False
-
- with pytest.raises(ValueError, match="Webhook timestamp is too new"):
- with time_machine.travel(self.fake_now - timedelta(minutes=6)):
- assert verify(payload=payload, headers=headers, secret=secret) is False
-
- # wrong secret
- with pytest.raises(ValueError, match=r"Bad secret"):
- verify(payload=payload, headers=headers, secret="invalid secret")
-
- invalid_signature_message = "None of the given webhook signatures match the expected signature"
- with pytest.raises(ValueError, match=invalid_signature_message):
- verify(
- payload=payload,
- headers=headers,
- secret=base64.b64encode(b"foo").decode("utf-8"),
- )
-
- # multiple signatures
- invalid_signature = base64.b64encode(b"my_sig").decode("utf-8")
- assert (
- verify(
- payload=payload,
- headers={**headers, "finch-signature": f"v1,{invalid_signature} v1,{signature}"},
- secret=secret,
- )
- is None
- )
-
- # different signature version
- with pytest.raises(ValueError, match=invalid_signature_message):
- verify(
- payload=payload,
- headers={**headers, "finch-signature": f"v2,{signature}"},
- secret=secret,
- )
-
- assert (
- verify(
- payload=payload,
- headers={**headers, "finch-signature": f"v2,{signature} v1,{signature}"},
- secret=secret,
- )
- is None
- )
-
- # missing version
- with pytest.raises(ValueError, match=invalid_signature_message):
- verify(
- payload=payload,
- headers={**headers, "finch-signature": signature},
- secret=secret,
- )
-
- # non-string payload
- with pytest.raises(ValueError, match=r"Webhook body should be a string"):
- verify(
- payload=cast(Any, {"payload": payload}),
- headers=headers,
- secret=secret,
- )
From 7961a22b10e052807d02fd09c9ae7d07c30391af Mon Sep 17 00:00:00 2001
From: Robert Craigie
Date: Wed, 27 Mar 2024 17:07:04 +0000
Subject: [PATCH 10/13] chore: revert temporary commit
---
README.md | 23 +++
api.md | 12 ++
src/finch/_client.py | 132 +++++++++++++++
src/finch/resources/__init__.py | 3 +
src/finch/resources/access_tokens.py | 39 ++++-
src/finch/resources/webhooks.py | 221 ++++++++++++++++++++++++++
tests/api_resources/test_top_level.py | 17 ++
tests/api_resources/test_webhooks.py | 214 +++++++++++++++++++++++++
8 files changed, 654 insertions(+), 7 deletions(-)
create mode 100644 src/finch/resources/webhooks.py
create mode 100644 tests/api_resources/test_top_level.py
create mode 100644 tests/api_resources/test_webhooks.py
diff --git a/README.md b/README.md
index 191c1ee5..8e807ac0 100644
--- a/README.md
+++ b/README.md
@@ -142,6 +142,29 @@ page = client.hris.directory.list()
print(page.page)
```
+## Webhook Verification
+
+We provide helper methods for verifying that a webhook request came from Finch, and not a malicious third party.
+
+You can use `finch.webhooks.verify_signature(body: string, headers, secret?) -> None` or `finch.webhooks.unwrap(body: string, headers, secret?) -> Payload`,
+both of which will raise an error if the signature is invalid.
+
+Note that the "body" parameter must be the raw JSON string sent from the server (do not parse it first).
+The `.unwrap()` method can parse this JSON for you into a `Payload` object.
+
+For example, in [FastAPI](https://fastapi.tiangolo.com/):
+
+```py
+@app.post('/my-webhook-handler')
+async def handler(request: Request):
+ body = await request.body()
+ secret = os.environ['FINCH_WEBHOOK_SECRET'] # env var used by default; explicit here.
+ payload = client.webhooks.unwrap(body, request.headers, secret)
+ print(payload)
+
+ return {'ok': True}
+```
+
## Handling errors
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `finch.APIConnectionError` is raised.
diff --git a/api.md b/api.md
index 5ca9c362..80dfe151 100644
--- a/api.md
+++ b/api.md
@@ -4,6 +4,13 @@
from finch.types import ConnectionStatusType, OperationSupport, OperationSupportMatrix, Paging
```
+# Finch
+
+Methods:
+
+- client.get_auth_url(\*args) -> str
+- client.with_access_token(\*args) -> Self
+
# AccessTokens
Types:
@@ -188,6 +195,11 @@ from finch.types import (
)
```
+Methods:
+
+- client.webhooks.unwrap(\*args) -> WebhookEvent
+- client.webhooks.verify_signature(\*args) -> None
+
# RequestForwarding
Types:
diff --git a/src/finch/_client.py b/src/finch/_client.py
index 9afd1c69..cddb281d 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -56,6 +56,7 @@ class Finch(SyncAPIClient):
hris: resources.HRIS
providers: resources.Providers
account: resources.Account
+ webhooks: resources.Webhooks
request_forwarding: resources.RequestForwarding
jobs: resources.Jobs
sandbox: resources.Sandbox
@@ -156,6 +157,7 @@ def __init__(
self.hris = resources.HRIS(self)
self.providers = resources.Providers(self)
self.account = resources.Account(self)
+ self.webhooks = resources.Webhooks(self)
self.request_forwarding = resources.RequestForwarding(self)
self.jobs = resources.Jobs(self)
self.sandbox = resources.Sandbox(self)
@@ -299,6 +301,70 @@ def copy(
# client.with_options(timeout=10).foo.create(...)
with_options = copy
+ def get_access_token(
+ self,
+ code: str,
+ *,
+ redirect_uri: str | None = None,
+ ) -> str:
+ """DEPRECATED: use client.access_tokens.create instead."""
+ if self.client_id is None:
+ raise ValueError("Expected client_id to be set in order to call get_access_token")
+
+ if self.client_secret is None:
+ raise ValueError("Expected client_secret to be set in order to call get_access_token")
+
+ response = self.post(
+ "/auth/token",
+ body={
+ "client_id": self.client_id,
+ "client_secret": self.client_secret,
+ "code": code,
+ "redirect_uri": redirect_uri,
+ },
+ options={"headers": {"Authorization": Omit()}},
+ cast_to=httpx.Response,
+ )
+ data = response.json()
+ return str(data["access_token"])
+
+ def get_auth_url(
+ self,
+ *,
+ products: str,
+ redirect_uri: str,
+ sandbox: bool,
+ ) -> str:
+ """
+ Returns the authorization url which can be visited in order to obtain an
+ authorization code from Finch. The authorization code can then be exchanged for
+ an access token for the Finch api by calling get_access_token().
+ """
+ if self.client_id is None:
+ raise ValueError("Expected the client_id to be set in order to call get_auth_url")
+
+ return str(
+ httpx.URL(
+ "https://connect.tryfinch.com/authorize",
+ params={
+ "client_id": self.client_id,
+ "products": products,
+ "redirect_uri": redirect_uri,
+ "sandbox": sandbox,
+ },
+ )
+ )
+
+ def with_access_token(
+ self,
+ access_token: str,
+ ) -> Self:
+ """
+ Returns a copy of the current Finch client with the given access token for
+ authentication.
+ """
+ return self.with_options(access_token=access_token)
+
@override
def _make_status_error(
self,
@@ -338,6 +404,7 @@ class AsyncFinch(AsyncAPIClient):
hris: resources.AsyncHRIS
providers: resources.AsyncProviders
account: resources.AsyncAccount
+ webhooks: resources.AsyncWebhooks
request_forwarding: resources.AsyncRequestForwarding
jobs: resources.AsyncJobs
sandbox: resources.AsyncSandbox
@@ -438,6 +505,7 @@ def __init__(
self.hris = resources.AsyncHRIS(self)
self.providers = resources.AsyncProviders(self)
self.account = resources.AsyncAccount(self)
+ self.webhooks = resources.AsyncWebhooks(self)
self.request_forwarding = resources.AsyncRequestForwarding(self)
self.jobs = resources.AsyncJobs(self)
self.sandbox = resources.AsyncSandbox(self)
@@ -581,6 +649,70 @@ def copy(
# client.with_options(timeout=10).foo.create(...)
with_options = copy
+ async def get_access_token(
+ self,
+ code: str,
+ *,
+ redirect_uri: str | None = None,
+ ) -> str:
+ """DEPRECATED: use client.access_tokens.create instead."""
+ if self.client_id is None:
+ raise ValueError("Expected client_id to be set in order to call get_access_token")
+
+ if self.client_secret is None:
+ raise ValueError("Expected client_secret to be set in order to call get_access_token")
+
+ response = await self.post(
+ "/auth/token",
+ body={
+ "client_id": self.client_id,
+ "client_secret": self.client_secret,
+ "code": code,
+ "redirect_uri": redirect_uri,
+ },
+ options={"headers": {"Authorization": Omit()}},
+ cast_to=httpx.Response,
+ )
+ data = response.json()
+ return str(data["access_token"])
+
+ def get_auth_url(
+ self,
+ *,
+ products: str,
+ redirect_uri: str,
+ sandbox: bool,
+ ) -> str:
+ """
+ Returns the authorization url which can be visited in order to obtain an
+ authorization code from Finch. The authorization code can then be exchanged for
+ an access token for the Finch api by calling get_access_token().
+ """
+ if self.client_id is None:
+ raise ValueError("Expected the client_id to be set in order to call get_auth_url")
+
+ return str(
+ httpx.URL(
+ "https://connect.tryfinch.com/authorize",
+ params={
+ "client_id": self.client_id,
+ "products": products,
+ "redirect_uri": redirect_uri,
+ "sandbox": sandbox,
+ },
+ )
+ )
+
+ def with_access_token(
+ self,
+ access_token: str,
+ ) -> Self:
+ """
+ Returns a copy of the current Finch client with the given access token for
+ authentication.
+ """
+ return self.with_options(access_token=access_token)
+
@override
def _make_status_error(
self,
diff --git a/src/finch/resources/__init__.py b/src/finch/resources/__init__.py
index 04bef46f..d5f226e9 100644
--- a/src/finch/resources/__init__.py
+++ b/src/finch/resources/__init__.py
@@ -32,6 +32,7 @@
SandboxWithStreamingResponse,
AsyncSandboxWithStreamingResponse,
)
+from .webhooks import Webhooks, AsyncWebhooks
from .providers import (
Providers,
AsyncProviders,
@@ -82,6 +83,8 @@
"AsyncAccountWithRawResponse",
"AccountWithStreamingResponse",
"AsyncAccountWithStreamingResponse",
+ "Webhooks",
+ "AsyncWebhooks",
"RequestForwarding",
"AsyncRequestForwarding",
"RequestForwardingWithRawResponse",
diff --git a/src/finch/resources/access_tokens.py b/src/finch/resources/access_tokens.py
index 8b5086d7..7e4fad17 100644
--- a/src/finch/resources/access_tokens.py
+++ b/src/finch/resources/access_tokens.py
@@ -7,10 +7,7 @@
from .. import _legacy_response
from ..types import CreateAccessTokenResponse, access_token_create_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
-from .._utils import (
- maybe_transform,
- async_maybe_transform,
-)
+from .._utils import is_given, maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
@@ -56,13 +53,27 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
+ if not is_given(client_id):
+ if self._client.client_id is None:
+ raise ValueError(
+ "client_id must be provided as an argument or with the FINCH_CLIENT_ID environment variable"
+ )
+ client_id = self._client.client_id
+
+ if not is_given(client_secret):
+ if self._client.client_secret is None:
+ raise ValueError(
+ "client_secret must be provided as an argument or with the FINCH_CLIENT_SECRET environment variable"
+ )
+ client_secret = self._client.client_secret
+
return self._post(
"/auth/token",
body=maybe_transform(
{
- "code": code,
"client_id": client_id,
"client_secret": client_secret,
+ "code": code,
"redirect_uri": redirect_uri,
},
access_token_create_params.AccessTokenCreateParams,
@@ -109,13 +120,27 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
+ if not is_given(client_id):
+ if self._client.client_id is None:
+ raise ValueError(
+ "client_id must be provided as an argument or with the FINCH_CLIENT_ID environment variable"
+ )
+ client_id = self._client.client_id
+
+ if not is_given(client_secret):
+ if self._client.client_secret is None:
+ raise ValueError(
+ "client_secret must be provided as an argument or with the FINCH_CLIENT_SECRET environment variable"
+ )
+ client_secret = self._client.client_secret
+
return await self._post(
"/auth/token",
- body=await async_maybe_transform(
+ body=maybe_transform(
{
- "code": code,
"client_id": client_id,
"client_secret": client_secret,
+ "code": code,
"redirect_uri": redirect_uri,
},
access_token_create_params.AccessTokenCreateParams,
diff --git a/src/finch/resources/webhooks.py b/src/finch/resources/webhooks.py
new file mode 100644
index 00000000..0fe50944
--- /dev/null
+++ b/src/finch/resources/webhooks.py
@@ -0,0 +1,221 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import hmac
+import json
+import math
+import base64
+import hashlib
+from typing import cast
+from datetime import datetime, timezone, timedelta
+
+from ..types import WebhookEvent
+from .._types import (
+ HeadersLike,
+)
+from .._utils import (
+ get_required_header,
+)
+from .._models import construct_type
+from .._resource import SyncAPIResource, AsyncAPIResource
+
+__all__ = ["Webhooks", "AsyncWebhooks"]
+
+
+class Webhooks(SyncAPIResource):
+ def unwrap(
+ self,
+ payload: str | bytes,
+ headers: HeadersLike,
+ *,
+ secret: str | None = None,
+ ) -> WebhookEvent:
+ """Validates that the given payload was sent by Finch and parses the payload."""
+ self.verify_signature(payload=payload, headers=headers, secret=secret)
+ return cast(
+ WebhookEvent,
+ construct_type(
+ value=json.loads(payload),
+ type_=WebhookEvent, # type: ignore[arg-type]
+ ),
+ )
+
+ def verify_signature(
+ self,
+ payload: str | bytes,
+ headers: HeadersLike,
+ *,
+ secret: str | None = None,
+ ) -> None:
+ """Validates whether or not the webhook payload was sent by Finch.
+
+ An error will be raised if the webhook payload was not sent by Finch.
+ """
+ if secret is None:
+ secret = self._client.webhook_secret
+
+ if secret is None:
+ raise ValueError(
+ "The webhook secret must either be set using the env var, FINCH_WEBHOOK_SECRET, on the client class, Finch(webhook_secret='123'), or passed to this function"
+ )
+
+ try:
+ parsedSecret = base64.b64decode(secret)
+ except Exception as err:
+ raise ValueError("Bad secret") from err
+
+ msg_id = get_required_header(headers, "finch-event-id")
+ msg_timestamp = get_required_header(headers, "finch-timestamp")
+
+ # validate the timestamp
+ webhook_tolerance = timedelta(minutes=5)
+ now = datetime.now(tz=timezone.utc)
+
+ try:
+ timestamp = datetime.fromtimestamp(float(msg_timestamp), tz=timezone.utc)
+ except Exception as err:
+ raise ValueError("Invalid timestamp header: " + msg_timestamp + ". Could not convert to timestamp") from err
+
+ # too old
+ if timestamp < (now - webhook_tolerance):
+ raise ValueError("Webhook timestamp is too old")
+
+ # too new
+ if timestamp > (now + webhook_tolerance):
+ raise ValueError("Webhook timestamp is too new")
+
+ # create the signature
+ body = payload.decode("utf-8") if isinstance(payload, bytes) else payload
+ if not isinstance(body, str): # pyright: ignore[reportUnnecessaryIsInstance]
+ raise ValueError(
+ "Webhook body should be a string of JSON (or bytes which can be decoded to a utf-8 string), not a parsed dictionary."
+ )
+
+ timestamp_str = str(math.floor(timestamp.replace(tzinfo=timezone.utc).timestamp()))
+
+ to_sign = f"{msg_id}.{timestamp_str}.{body}".encode()
+ expected_signature = hmac.new(parsedSecret, to_sign, hashlib.sha256).digest()
+
+ msg_signature = get_required_header(headers, "finch-signature")
+
+ # Signature header can contain multiple signatures delimited by spaces
+ passed_sigs = msg_signature.split(" ")
+
+ for versioned_sig in passed_sigs:
+ values = versioned_sig.split(",")
+ if len(values) != 2:
+ # signature is not formatted like {version},{signature}
+ continue
+
+ (version, signature) = values
+
+ # Only verify prefix v1
+ if version != "v1":
+ continue
+
+ sig_bytes = base64.b64decode(signature)
+ if hmac.compare_digest(expected_signature, sig_bytes):
+ # valid!
+ return None
+
+ raise ValueError("None of the given webhook signatures match the expected signature")
+
+
+class AsyncWebhooks(AsyncAPIResource):
+ def unwrap(
+ self,
+ payload: str | bytes,
+ headers: HeadersLike,
+ *,
+ secret: str | None = None,
+ ) -> WebhookEvent:
+ """Validates that the given payload was sent by Finch and parses the payload."""
+ self.verify_signature(payload=payload, headers=headers, secret=secret)
+ return cast(
+ WebhookEvent,
+ construct_type(
+ value=json.loads(payload),
+ type_=WebhookEvent, # type: ignore[arg-type]
+ ),
+ )
+
+ def verify_signature(
+ self,
+ payload: str | bytes,
+ headers: HeadersLike,
+ *,
+ secret: str | None = None,
+ ) -> None:
+ """Validates whether or not the webhook payload was sent by Finch.
+
+ An error will be raised if the webhook payload was not sent by Finch.
+ """
+ if secret is None:
+ secret = self._client.webhook_secret
+
+ if secret is None:
+ raise ValueError(
+ "The webhook secret must either be set using the env var, FINCH_WEBHOOK_SECRET, on the client class, Finch(webhook_secret='123'), or passed to this function"
+ )
+
+ try:
+ parsedSecret = base64.b64decode(secret)
+ except Exception as err:
+ raise ValueError("Bad secret") from err
+
+ msg_id = get_required_header(headers, "finch-event-id")
+ msg_timestamp = get_required_header(headers, "finch-timestamp")
+
+ # validate the timestamp
+ webhook_tolerance = timedelta(minutes=5)
+ now = datetime.now(tz=timezone.utc)
+
+ try:
+ timestamp = datetime.fromtimestamp(float(msg_timestamp), tz=timezone.utc)
+ except Exception as err:
+ raise ValueError("Invalid timestamp header: " + msg_timestamp + ". Could not convert to timestamp") from err
+
+ # too old
+ if timestamp < (now - webhook_tolerance):
+ raise ValueError("Webhook timestamp is too old")
+
+ # too new
+ if timestamp > (now + webhook_tolerance):
+ raise ValueError("Webhook timestamp is too new")
+
+ # create the signature
+ body = payload.decode("utf-8") if isinstance(payload, bytes) else payload
+ if not isinstance(body, str): # pyright: ignore[reportUnnecessaryIsInstance]
+ raise ValueError(
+ "Webhook body should be a string of JSON (or bytes which can be decoded to a utf-8 string), not a parsed dictionary."
+ )
+
+ timestamp_str = str(math.floor(timestamp.replace(tzinfo=timezone.utc).timestamp()))
+
+ to_sign = f"{msg_id}.{timestamp_str}.{body}".encode()
+ expected_signature = hmac.new(parsedSecret, to_sign, hashlib.sha256).digest()
+
+ msg_signature = get_required_header(headers, "finch-signature")
+
+ # Signature header can contain multiple signatures delimited by spaces
+ passed_sigs = msg_signature.split(" ")
+
+ for versioned_sig in passed_sigs:
+ values = versioned_sig.split(",")
+ if len(values) != 2:
+ # signature is not formatted like {version},{signature}
+ continue
+
+ (version, signature) = values
+
+ # Only verify prefix v1
+ if version != "v1":
+ continue
+
+ sig_bytes = base64.b64decode(signature)
+ if hmac.compare_digest(expected_signature, sig_bytes):
+ # valid!
+ return None
+
+ raise ValueError("None of the given webhook signatures match the expected signature")
diff --git a/tests/api_resources/test_top_level.py b/tests/api_resources/test_top_level.py
new file mode 100644
index 00000000..e1c15ec0
--- /dev/null
+++ b/tests/api_resources/test_top_level.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+
+import pytest
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestTopLevel:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+
+class TestAsyncTopLevel:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
diff --git a/tests/api_resources/test_webhooks.py b/tests/api_resources/test_webhooks.py
new file mode 100644
index 00000000..72b7d6af
--- /dev/null
+++ b/tests/api_resources/test_webhooks.py
@@ -0,0 +1,214 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+import base64
+from typing import Any, cast
+from datetime import datetime, timezone, timedelta
+
+import pytest
+import time_machine
+from pydantic import BaseModel
+
+from finch import Finch, AsyncFinch
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestWebhooks:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ timestamp = "1676312382"
+ fake_now = datetime.fromtimestamp(float(timestamp), tz=timezone.utc)
+
+ payload = """{"company_id":"720be419-0293-4d32-a707-32179b0827ab"}"""
+ signature = "m7y0TV2C+hlHxU42wCieApTSTaA8/047OAplBqxIV/s="
+ headers = {
+ "Finch-Event-Id": "msg_2Lh9KRb0pzN4LePd3XiA4v12Axj",
+ "finch-timestamp": timestamp,
+ "finch-signature": f"v1,{signature}",
+ }
+ secret = "5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH"
+
+ @time_machine.travel(fake_now)
+ def test_unwrap(self, client: Finch) -> None:
+ payload = self.payload
+ headers = self.headers
+ secret = self.secret
+
+ obj = client.webhooks.unwrap(payload, headers, secret=secret)
+ assert isinstance(obj, BaseModel)
+
+ @time_machine.travel(fake_now)
+ def test_verify_signature(self, client: Finch) -> None:
+ payload = self.payload
+ headers = self.headers
+ secret = self.secret
+ signature = self.signature
+ verify = client.webhooks.verify_signature
+
+ assert verify(payload=payload, headers=headers, secret=secret) is None
+
+ with pytest.raises(ValueError, match="Webhook timestamp is too old"):
+ with time_machine.travel(self.fake_now + timedelta(minutes=6)):
+ assert verify(payload=payload, headers=headers, secret=secret) is False
+
+ with pytest.raises(ValueError, match="Webhook timestamp is too new"):
+ with time_machine.travel(self.fake_now - timedelta(minutes=6)):
+ assert verify(payload=payload, headers=headers, secret=secret) is False
+
+ # wrong secret
+ with pytest.raises(ValueError, match=r"Bad secret"):
+ verify(payload=payload, headers=headers, secret="invalid secret")
+
+ invalid_signature_message = "None of the given webhook signatures match the expected signature"
+ with pytest.raises(ValueError, match=invalid_signature_message):
+ verify(
+ payload=payload,
+ headers=headers,
+ secret=base64.b64encode(b"foo").decode("utf-8"),
+ )
+
+ # multiple signatures
+ invalid_signature = base64.b64encode(b"my_sig").decode("utf-8")
+ assert (
+ verify(
+ payload=payload,
+ headers={**headers, "finch-signature": f"v1,{invalid_signature} v1,{signature}"},
+ secret=secret,
+ )
+ is None
+ )
+
+ # different signature version
+ with pytest.raises(ValueError, match=invalid_signature_message):
+ verify(
+ payload=payload,
+ headers={**headers, "finch-signature": f"v2,{signature}"},
+ secret=secret,
+ )
+
+ assert (
+ verify(
+ payload=payload,
+ headers={**headers, "finch-signature": f"v2,{signature} v1,{signature}"},
+ secret=secret,
+ )
+ is None
+ )
+
+ # missing version
+ with pytest.raises(ValueError, match=invalid_signature_message):
+ verify(
+ payload=payload,
+ headers={**headers, "finch-signature": signature},
+ secret=secret,
+ )
+
+ # non-string payload
+ with pytest.raises(ValueError, match=r"Webhook body should be a string"):
+ verify(
+ payload=cast(Any, {"payload": payload}),
+ headers=headers,
+ secret=secret,
+ )
+
+
+class TestAsyncWebhooks:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ timestamp = "1676312382"
+ fake_now = datetime.fromtimestamp(float(timestamp), tz=timezone.utc)
+
+ payload = """{"company_id":"720be419-0293-4d32-a707-32179b0827ab"}"""
+ signature = "m7y0TV2C+hlHxU42wCieApTSTaA8/047OAplBqxIV/s="
+ headers = {
+ "Finch-Event-Id": "msg_2Lh9KRb0pzN4LePd3XiA4v12Axj",
+ "finch-timestamp": timestamp,
+ "finch-signature": f"v1,{signature}",
+ }
+ secret = "5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH"
+
+ @time_machine.travel(fake_now)
+ def test_unwrap(self, async_client: AsyncFinch) -> None:
+ payload = self.payload
+ headers = self.headers
+ secret = self.secret
+
+ obj = async_client.webhooks.unwrap(payload, headers, secret=secret)
+ assert isinstance(obj, BaseModel)
+
+ @time_machine.travel(fake_now)
+ def test_verify_signature(self, async_client: AsyncFinch) -> None:
+ payload = self.payload
+ headers = self.headers
+ secret = self.secret
+ signature = self.signature
+ verify = async_client.webhooks.verify_signature
+
+ assert verify(payload=payload, headers=headers, secret=secret) is None
+
+ with pytest.raises(ValueError, match="Webhook timestamp is too old"):
+ with time_machine.travel(self.fake_now + timedelta(minutes=6)):
+ assert verify(payload=payload, headers=headers, secret=secret) is False
+
+ with pytest.raises(ValueError, match="Webhook timestamp is too new"):
+ with time_machine.travel(self.fake_now - timedelta(minutes=6)):
+ assert verify(payload=payload, headers=headers, secret=secret) is False
+
+ # wrong secret
+ with pytest.raises(ValueError, match=r"Bad secret"):
+ verify(payload=payload, headers=headers, secret="invalid secret")
+
+ invalid_signature_message = "None of the given webhook signatures match the expected signature"
+ with pytest.raises(ValueError, match=invalid_signature_message):
+ verify(
+ payload=payload,
+ headers=headers,
+ secret=base64.b64encode(b"foo").decode("utf-8"),
+ )
+
+ # multiple signatures
+ invalid_signature = base64.b64encode(b"my_sig").decode("utf-8")
+ assert (
+ verify(
+ payload=payload,
+ headers={**headers, "finch-signature": f"v1,{invalid_signature} v1,{signature}"},
+ secret=secret,
+ )
+ is None
+ )
+
+ # different signature version
+ with pytest.raises(ValueError, match=invalid_signature_message):
+ verify(
+ payload=payload,
+ headers={**headers, "finch-signature": f"v2,{signature}"},
+ secret=secret,
+ )
+
+ assert (
+ verify(
+ payload=payload,
+ headers={**headers, "finch-signature": f"v2,{signature} v1,{signature}"},
+ secret=secret,
+ )
+ is None
+ )
+
+ # missing version
+ with pytest.raises(ValueError, match=invalid_signature_message):
+ verify(
+ payload=payload,
+ headers={**headers, "finch-signature": signature},
+ secret=secret,
+ )
+
+ # non-string payload
+ with pytest.raises(ValueError, match=r"Webhook body should be a string"):
+ verify(
+ payload=cast(Any, {"payload": payload}),
+ headers=headers,
+ secret=secret,
+ )
From 6ee479969a3ac25ed98d5e93bbcacf58d1171529 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 28 Mar 2024 15:30:27 +0000
Subject: [PATCH 11/13] feat(package): export default constants (#334)
---
src/finch/__init__.py | 4 ++++
src/finch/_base_client.py | 6 +++---
src/finch/_client.py | 6 +++---
src/finch/_constants.py | 2 +-
4 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/finch/__init__.py b/src/finch/__init__.py
index 4f268071..61b87181 100644
--- a/src/finch/__init__.py
+++ b/src/finch/__init__.py
@@ -7,6 +7,7 @@
from ._models import BaseModel
from ._version import __title__, __version__
from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse
+from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS
from ._exceptions import (
APIError,
FinchError,
@@ -58,6 +59,9 @@
"AsyncFinch",
"file_from_path",
"BaseModel",
+ "DEFAULT_TIMEOUT",
+ "DEFAULT_MAX_RETRIES",
+ "DEFAULT_CONNECTION_LIMITS",
]
_setup_logging()
diff --git a/src/finch/_base_client.py b/src/finch/_base_client.py
index f431128e..7a8595c1 100644
--- a/src/finch/_base_client.py
+++ b/src/finch/_base_client.py
@@ -71,13 +71,13 @@
extract_response_type,
)
from ._constants import (
- DEFAULT_LIMITS,
DEFAULT_TIMEOUT,
MAX_RETRY_DELAY,
DEFAULT_MAX_RETRIES,
INITIAL_RETRY_DELAY,
RAW_RESPONSE_HEADER,
OVERRIDE_CAST_TO_HEADER,
+ DEFAULT_CONNECTION_LIMITS,
)
from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder
from ._exceptions import (
@@ -747,7 +747,7 @@ def __init__(
if http_client is not None:
raise ValueError("The `http_client` argument is mutually exclusive with `connection_pool_limits`")
else:
- limits = DEFAULT_LIMITS
+ limits = DEFAULT_CONNECTION_LIMITS
if transport is not None:
warnings.warn(
@@ -1294,7 +1294,7 @@ def __init__(
if http_client is not None:
raise ValueError("The `http_client` argument is mutually exclusive with `connection_pool_limits`")
else:
- limits = DEFAULT_LIMITS
+ limits = DEFAULT_CONNECTION_LIMITS
if transport is not None:
warnings.warn(
diff --git a/src/finch/_client.py b/src/finch/_client.py
index cddb281d..38ed6d91 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -30,8 +30,8 @@
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
from ._exceptions import APIStatusError
from ._base_client import (
- DEFAULT_LIMITS,
DEFAULT_MAX_RETRIES,
+ DEFAULT_CONNECTION_LIMITS,
SyncAPIClient,
AsyncAPIClient,
SyncHttpxClientWrapper,
@@ -273,7 +273,7 @@ def copy(
http_client = None
else:
- if self._limits is not DEFAULT_LIMITS:
+ if self._limits is not DEFAULT_CONNECTION_LIMITS:
connection_pool_limits = self._limits
else:
connection_pool_limits = None
@@ -621,7 +621,7 @@ def copy(
http_client = None
else:
- if self._limits is not DEFAULT_LIMITS:
+ if self._limits is not DEFAULT_CONNECTION_LIMITS:
connection_pool_limits = self._limits
else:
connection_pool_limits = None
diff --git a/src/finch/_constants.py b/src/finch/_constants.py
index 1d56f7fd..a2ac3b6f 100644
--- a/src/finch/_constants.py
+++ b/src/finch/_constants.py
@@ -8,7 +8,7 @@
# default timeout is 1 minute
DEFAULT_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0)
DEFAULT_MAX_RETRIES = 2
-DEFAULT_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20)
+DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20)
INITIAL_RETRY_DELAY = 0.5
MAX_RETRY_DELAY = 8.0
From f44d11caf7c2869470d941025083e29b6104ef21 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 29 Mar 2024 14:09:28 +0000
Subject: [PATCH 12/13] fix(project): use absolute github links on PyPi (#335)
---
pyproject.toml | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index c6a548ec..c083bcc8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,7 +2,7 @@
name = "finch-api"
version = "0.16.8"
description = "The official Python library for the Finch API"
-readme = "README.md"
+dynamic = ["readme"]
license = "Apache-2.0"
authors = [
{ name = "Finch", email = "founders@tryfinch.com" },
@@ -88,7 +88,7 @@ typecheck = { chain = [
"typecheck:mypy" = "mypy ."
[build-system]
-requires = ["hatchling"]
+requires = ["hatchling", "hatch-fancy-pypi-readme"]
build-backend = "hatchling.build"
[tool.hatch.build]
@@ -99,6 +99,17 @@ include = [
[tool.hatch.build.targets.wheel]
packages = ["src/finch"]
+[tool.hatch.metadata.hooks.fancy-pypi-readme]
+content-type = "text/markdown"
+
+[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
+path = "README.md"
+
+[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
+# replace relative links with absolute links
+pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)'
+replacement = '[\1](https://github.com/Finch-API/finch-api-python/tree/main/\g<2>)'
+
[tool.black]
line-length = 120
target-version = ["py37"]
From 332278f8376ba2017bd2cae657a6eedc89e7b691 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 29 Mar 2024 14:09:44 +0000
Subject: [PATCH 13/13] release: 0.17.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++
pyproject.toml | 2 +-
src/finch/_version.py | 2 +-
4 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index c0cedeb0..6db19b95 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.16.8"
+ ".": "0.17.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 87d32a9c..1b07d9d6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,40 @@
# Changelog
+## 0.17.0 (2024-03-29)
+
+Full Changelog: [v0.16.8...v0.17.0](https://github.com/Finch-API/finch-api-python/compare/v0.16.8...v0.17.0)
+
+### Features
+
+* **package:** export default constants ([#334](https://github.com/Finch-API/finch-api-python/issues/334)) ([6ee4799](https://github.com/Finch-API/finch-api-python/commit/6ee479969a3ac25ed98d5e93bbcacf58d1171529))
+
+
+### Bug Fixes
+
+* **project:** use absolute github links on PyPi ([#335](https://github.com/Finch-API/finch-api-python/issues/335)) ([f44d11c](https://github.com/Finch-API/finch-api-python/commit/f44d11caf7c2869470d941025083e29b6104ef21))
+* revert regression with 3.7 support ([#332](https://github.com/Finch-API/finch-api-python/issues/332)) ([da0031c](https://github.com/Finch-API/finch-api-python/commit/da0031cd66a123f339a65ad63a731e97ad65383f))
+
+
+### Performance Improvements
+
+* cache TypeAdapters ([#324](https://github.com/Finch-API/finch-api-python/issues/324)) ([3bd22fe](https://github.com/Finch-API/finch-api-python/commit/3bd22fe8a9fe02f2700ac0b6387b00575cddc444))
+
+
+### Chores
+
+* **internal:** formatting change ([#330](https://github.com/Finch-API/finch-api-python/issues/330)) ([6b8829f](https://github.com/Finch-API/finch-api-python/commit/6b8829f4999a3e243d63f45126000b5ad2a6b9ef))
+* **internal:** loosen input type for util function ([#328](https://github.com/Finch-API/finch-api-python/issues/328)) ([3fdcf2e](https://github.com/Finch-API/finch-api-python/commit/3fdcf2e89f9ba3ef341e0402d3cfd528ad568af5))
+* **internal:** update generated pragma comment ([#327](https://github.com/Finch-API/finch-api-python/issues/327)) ([269569f](https://github.com/Finch-API/finch-api-python/commit/269569fdca6c03dc8202dab0b20e00c099020d65))
+* revert temporary commit ([7961a22](https://github.com/Finch-API/finch-api-python/commit/7961a22b10e052807d02fd09c9ae7d07c30391af))
+* temporary commit ([#333](https://github.com/Finch-API/finch-api-python/issues/333)) ([5e42474](https://github.com/Finch-API/finch-api-python/commit/5e42474c6a00a6ec3e8a11db753ffbecb6e9a1e3))
+
+
+### Documentation
+
+* **contributing:** fix typo ([#331](https://github.com/Finch-API/finch-api-python/issues/331)) ([15c71d5](https://github.com/Finch-API/finch-api-python/commit/15c71d5bc77fda5bb4b2f7aec53c75f49987ae3b))
+* fix typo in CONTRIBUTING.md ([#326](https://github.com/Finch-API/finch-api-python/issues/326)) ([98ba71b](https://github.com/Finch-API/finch-api-python/commit/98ba71b32ab2eaa1564b0fbab85cb2de9a0ea421))
+* **readme:** document how to make undocumented requests ([#329](https://github.com/Finch-API/finch-api-python/issues/329)) ([55bf27d](https://github.com/Finch-API/finch-api-python/commit/55bf27d677d81c1272b148ec37fdac8b5dd4fc68))
+
## 0.16.8 (2024-03-11)
Full Changelog: [v0.16.7...v0.16.8](https://github.com/Finch-API/finch-api-python/compare/v0.16.7...v0.16.8)
diff --git a/pyproject.toml b/pyproject.toml
index c083bcc8..6973bd5e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "finch-api"
-version = "0.16.8"
+version = "0.17.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 3cb66124..59183cc5 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__ = "0.16.8" # x-release-please-version
+__version__ = "0.17.0" # x-release-please-version