diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 187c937b..08eb6b17 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,13 +36,13 @@ jobs: run: ./scripts/lint build: - if: github.repository == 'stainless-sdks/finch-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork timeout-minutes: 10 name: build permissions: contents: read id-token: write - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/finch-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -61,12 +61,14 @@ jobs: run: rye build - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/finch-python' id: github-oidc uses: actions/github-script@v6 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball + if: github.repository == 'stainless-sdks/finch-python' env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 257e308d..44959ac4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.34.0" + ".": "1.35.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 9d73576a..ff867f70 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 46 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-6d0c6a1feba5ccb895a6779cd98c2a0ae87d6394f5e98a9da51f17258c4eb297.yml -openapi_spec_hash: ac3be0c8a992103e5f467fe1bcb20a81 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-bf86910e96e83e583689cf5d1a5c583268754026ec68288994fa6a969dc248f2.yml +openapi_spec_hash: 195038e056891afec204c49dadce3b95 config_hash: 5146b12344dae76238940989dac1e8a0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 10ed1e21..73b7e553 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## 1.35.0 (2025-09-02) + +Full Changelog: [v1.34.0...v1.35.0](https://github.com/Finch-API/finch-api-python/compare/v1.34.0...v1.35.0) + +### Features + +* **api:** api update ([7f1f3fc](https://github.com/Finch-API/finch-api-python/commit/7f1f3fcb12b896ae43df668d6825e6de895a0843)) +* **types:** replace List[str] with SequenceNotStr in params ([7d41d8f](https://github.com/Finch-API/finch-api-python/commit/7d41d8fe116a14351d2f6aa569733c039f9a071f)) + + +### Bug Fixes + +* avoid newer type syntax ([c180618](https://github.com/Finch-API/finch-api-python/commit/c18061816f2c5d81d958cbf0fd7fd16b95fa7371)) + + +### Chores + +* **internal:** add Sequence related utils ([1c99d3a](https://github.com/Finch-API/finch-api-python/commit/1c99d3a79c85da901f81bfc94daa64317aedef19)) +* **internal:** change ci workflow machines ([825d163](https://github.com/Finch-API/finch-api-python/commit/825d1637f7058c3d80092b6b07146653cc76432f)) +* **internal:** minor formatting change ([7f1c96d](https://github.com/Finch-API/finch-api-python/commit/7f1c96d1ef47db7be85a93e602bfa612e50f04c1)) +* **internal:** update pyright exclude list ([7b620cc](https://github.com/Finch-API/finch-api-python/commit/7b620cc5f0a89e2d1aab02065ff0af4e87b022ff)) +* update github action ([5067831](https://github.com/Finch-API/finch-api-python/commit/50678319366698ef0d8ea19b6ae6d383e8b3725c)) + ## 1.34.0 (2025-08-20) Full Changelog: [v1.33.0...v1.34.0](https://github.com/Finch-API/finch-api-python/compare/v1.33.0...v1.34.0) diff --git a/pyproject.toml b/pyproject.toml index 81c435c8..f6539a71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "finch-api" -version = "1.34.0" +version = "1.35.0" description = "The official Python library for the Finch API" dynamic = ["readme"] license = "Apache-2.0" @@ -148,6 +148,7 @@ exclude = [ "_dev", ".venv", ".nox", + ".git", ] reportImplicitOverride = true diff --git a/src/finch/_models.py b/src/finch/_models.py index b8387ce9..92f7c10b 100644 --- a/src/finch/_models.py +++ b/src/finch/_models.py @@ -304,7 +304,7 @@ def model_dump( exclude_none=exclude_none, ) - return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped + return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped @override def model_dump_json( diff --git a/src/finch/_types.py b/src/finch/_types.py index 202fb730..9a4666ba 100644 --- a/src/finch/_types.py +++ b/src/finch/_types.py @@ -13,10 +13,21 @@ Mapping, TypeVar, Callable, + Iterator, Optional, Sequence, ) -from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable +from typing_extensions import ( + Set, + Literal, + Protocol, + TypeAlias, + TypedDict, + SupportsIndex, + overload, + override, + runtime_checkable, +) import httpx import pydantic @@ -219,3 +230,26 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth follow_redirects: bool + + +_T_co = TypeVar("_T_co", covariant=True) + + +if TYPE_CHECKING: + # This works because str.__contains__ does not accept object (either in typeshed or at runtime) + # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + class SequenceNotStr(Protocol[_T_co]): + @overload + def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... + @overload + def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... + def __contains__(self, value: object, /) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self) -> Iterator[_T_co]: ... + def index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ... + def count(self, value: Any, /) -> int: ... + def __reversed__(self) -> Iterator[_T_co]: ... +else: + # just point this to a normal `Sequence` at runtime to avoid having to special case + # deserializing our custom sequence type + SequenceNotStr = Sequence diff --git a/src/finch/_utils/__init__.py b/src/finch/_utils/__init__.py index d4fda26f..ca547ce5 100644 --- a/src/finch/_utils/__init__.py +++ b/src/finch/_utils/__init__.py @@ -38,6 +38,7 @@ extract_type_arg as extract_type_arg, is_iterable_type as is_iterable_type, is_required_type as is_required_type, + is_sequence_type as is_sequence_type, is_annotated_type as is_annotated_type, is_type_alias_type as is_type_alias_type, strip_annotated_type as strip_annotated_type, diff --git a/src/finch/_utils/_transform.py b/src/finch/_utils/_transform.py index b0cc20a7..f0bcefd4 100644 --- a/src/finch/_utils/_transform.py +++ b/src/finch/_utils/_transform.py @@ -16,6 +16,7 @@ lru_cache, is_mapping, is_iterable, + is_sequence, ) from .._files import is_base64_file_input from ._typing import ( @@ -24,6 +25,7 @@ extract_type_arg, is_iterable_type, is_required_type, + is_sequence_type, is_annotated_type, strip_annotated_type, ) @@ -184,6 +186,8 @@ def _transform_recursive( (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) ): # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually # intended as an iterable, so we don't transform it. @@ -346,6 +350,8 @@ async def _async_transform_recursive( (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) ): # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually # intended as an iterable, so we don't transform it. diff --git a/src/finch/_utils/_typing.py b/src/finch/_utils/_typing.py index 1bac9542..845cd6b2 100644 --- a/src/finch/_utils/_typing.py +++ b/src/finch/_utils/_typing.py @@ -26,6 +26,11 @@ def is_list_type(typ: type) -> bool: return (get_origin(typ) or typ) == list +def is_sequence_type(typ: type) -> bool: + origin = get_origin(typ) or typ + return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence + + def is_iterable_type(typ: type) -> bool: """If the given type is `typing.Iterable[T]`""" origin = get_origin(typ) or typ diff --git a/src/finch/_version.py b/src/finch/_version.py index e42e8ee5..468fd7c0 100644 --- a/src/finch/_version.py +++ b/src/finch/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "finch" -__version__ = "1.34.0" # x-release-please-version +__version__ = "1.35.0" # x-release-please-version diff --git a/src/finch/resources/hris/benefits/individuals.py b/src/finch/resources/hris/benefits/individuals.py index af0ad5e4..f9662196 100644 --- a/src/finch/resources/hris/benefits/individuals.py +++ b/src/finch/resources/hris/benefits/individuals.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import List, Iterable +from typing import Iterable import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -170,7 +170,7 @@ def unenroll_many( self, benefit_id: str, *, - individual_ids: List[str] | NotGiven = NOT_GIVEN, + individual_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -349,7 +349,7 @@ async def unenroll_many( self, benefit_id: str, *, - individual_ids: List[str] | NotGiven = NOT_GIVEN, + individual_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/finch/resources/hris/directory.py b/src/finch/resources/hris/directory.py index aa60f2f3..e4e6827e 100644 --- a/src/finch/resources/hris/directory.py +++ b/src/finch/resources/hris/directory.py @@ -241,7 +241,7 @@ def __init__(self, directory: Directory) -> None: ) self.list_individuals = ( # pyright: ignore[reportDeprecated] _legacy_response.to_raw_response_wrapper( - directory.list_individuals # pyright: ignore[reportDeprecated], + directory.list_individuals, # pyright: ignore[reportDeprecated], ) ) @@ -255,7 +255,7 @@ def __init__(self, directory: AsyncDirectory) -> None: ) self.list_individuals = ( # pyright: ignore[reportDeprecated] _legacy_response.async_to_raw_response_wrapper( - directory.list_individuals # pyright: ignore[reportDeprecated], + directory.list_individuals, # pyright: ignore[reportDeprecated], ) ) @@ -269,7 +269,7 @@ def __init__(self, directory: Directory) -> None: ) self.list_individuals = ( # pyright: ignore[reportDeprecated] to_streamed_response_wrapper( - directory.list_individuals # pyright: ignore[reportDeprecated], + directory.list_individuals, # pyright: ignore[reportDeprecated], ) ) @@ -283,6 +283,6 @@ def __init__(self, directory: AsyncDirectory) -> None: ) self.list_individuals = ( # pyright: ignore[reportDeprecated] async_to_streamed_response_wrapper( - directory.list_individuals # pyright: ignore[reportDeprecated], + directory.list_individuals, # pyright: ignore[reportDeprecated], ) ) diff --git a/src/finch/resources/hris/documents.py b/src/finch/resources/hris/documents.py index d4609a6b..ce3085e8 100644 --- a/src/finch/resources/hris/documents.py +++ b/src/finch/resources/hris/documents.py @@ -8,7 +8,7 @@ import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -44,7 +44,7 @@ def with_streaming_response(self) -> DocumentsWithStreamingResponse: def list( self, *, - individual_ids: List[str] | NotGiven = NOT_GIVEN, + individual_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, types: List[Literal["w4_2020", "w4_2005"]] | NotGiven = NOT_GIVEN, @@ -163,7 +163,7 @@ def with_streaming_response(self) -> AsyncDocumentsWithStreamingResponse: async def list( self, *, - individual_ids: List[str] | NotGiven = NOT_GIVEN, + individual_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, types: List[Literal["w4_2020", "w4_2005"]] | NotGiven = NOT_GIVEN, diff --git a/src/finch/resources/payroll/pay_groups.py b/src/finch/resources/payroll/pay_groups.py index bcd7854f..da646900 100644 --- a/src/finch/resources/payroll/pay_groups.py +++ b/src/finch/resources/payroll/pay_groups.py @@ -2,12 +2,10 @@ from __future__ import annotations -from typing import List - import httpx from ... import _legacy_response -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -78,7 +76,7 @@ def list( self, *, individual_id: str | NotGiven = NOT_GIVEN, - pay_frequencies: List[str] | NotGiven = NOT_GIVEN, + pay_frequencies: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -175,7 +173,7 @@ def list( self, *, individual_id: str | NotGiven = NOT_GIVEN, - pay_frequencies: List[str] | NotGiven = NOT_GIVEN, + pay_frequencies: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/finch/resources/sandbox/connections/accounts.py b/src/finch/resources/sandbox/connections/accounts.py index b8c45db6..956cd971 100644 --- a/src/finch/resources/sandbox/connections/accounts.py +++ b/src/finch/resources/sandbox/connections/accounts.py @@ -2,13 +2,12 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -48,7 +47,7 @@ def create( company_id: str, provider_id: str, authentication_type: Literal["credential", "api_token", "oauth", "assisted"] | NotGiven = NOT_GIVEN, - products: List[str] | NotGiven = NOT_GIVEN, + products: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -151,7 +150,7 @@ async def create( company_id: str, provider_id: str, authentication_type: Literal["credential", "api_token", "oauth", "assisted"] | NotGiven = NOT_GIVEN, - products: List[str] | NotGiven = NOT_GIVEN, + products: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/finch/resources/sandbox/connections/connections.py b/src/finch/resources/sandbox/connections/connections.py index fd485902..146e6739 100644 --- a/src/finch/resources/sandbox/connections/connections.py +++ b/src/finch/resources/sandbox/connections/connections.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal import httpx @@ -16,7 +15,7 @@ AccountsWithStreamingResponse, AsyncAccountsWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -58,7 +57,7 @@ def create( provider_id: str, authentication_type: Literal["credential", "api_token", "oauth", "assisted"] | NotGiven = NOT_GIVEN, employee_size: int | NotGiven = NOT_GIVEN, - products: List[str] | NotGiven = NOT_GIVEN, + products: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -132,7 +131,7 @@ async def create( provider_id: str, authentication_type: Literal["credential", "api_token", "oauth", "assisted"] | NotGiven = NOT_GIVEN, employee_size: int | NotGiven = NOT_GIVEN, - products: List[str] | NotGiven = NOT_GIVEN, + products: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, 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 01f8b33e..28263e89 100644 --- a/src/finch/types/hris/benefits/individual_unenroll_many_params.py +++ b/src/finch/types/hris/benefits/individual_unenroll_many_params.py @@ -2,12 +2,13 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ...._types import SequenceNotStr + __all__ = ["IndividualUnenrollManyParams"] class IndividualUnenrollManyParams(TypedDict, total=False): - individual_ids: List[str] + individual_ids: SequenceNotStr[str] """Array of individual_ids to unenroll.""" diff --git a/src/finch/types/hris/document_list_params.py b/src/finch/types/hris/document_list_params.py index 15fff861..23b35355 100644 --- a/src/finch/types/hris/document_list_params.py +++ b/src/finch/types/hris/document_list_params.py @@ -5,11 +5,13 @@ from typing import List from typing_extensions import Literal, TypedDict +from ..._types import SequenceNotStr + __all__ = ["DocumentListParams"] class DocumentListParams(TypedDict, total=False): - individual_ids: List[str] + individual_ids: SequenceNotStr[str] """Comma-delimited list of stable Finch uuids for each individual. If empty, defaults to all individuals diff --git a/src/finch/types/hris/individual_retrieve_many_params.py b/src/finch/types/hris/individual_retrieve_many_params.py index 33a0480a..86686eac 100644 --- a/src/finch/types/hris/individual_retrieve_many_params.py +++ b/src/finch/types/hris/individual_retrieve_many_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import TypedDict +from ..._types import SequenceNotStr + __all__ = ["IndividualRetrieveManyParams", "Options", "Request"] @@ -15,7 +17,7 @@ class IndividualRetrieveManyParams(TypedDict, total=False): class Options(TypedDict, total=False): - include: List[str] + include: SequenceNotStr[str] class Request(TypedDict, total=False): diff --git a/src/finch/types/introspection.py b/src/finch/types/introspection.py index 30847577..cfe4fbc3 100644 --- a/src/finch/types/introspection.py +++ b/src/finch/types/introspection.py @@ -98,6 +98,12 @@ class Introspection(BaseModel): created for this connection """ + entity_ids: Optional[List[str]] = None + """Array of entity IDs associated with this connection.""" + + entity_mode: Optional[Literal["single", "multi"]] = None + """Indicates whether this connection manages a single entity or multiple entities.""" + manual: Optional[bool] = None """ Whether the connection associated with the `access_token` uses the Assisted diff --git a/src/finch/types/payroll/pay_group_list_params.py b/src/finch/types/payroll/pay_group_list_params.py index 1e33abf4..67a6044e 100644 --- a/src/finch/types/payroll/pay_group_list_params.py +++ b/src/finch/types/payroll/pay_group_list_params.py @@ -2,13 +2,14 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ..._types import SequenceNotStr + __all__ = ["PayGroupListParams"] class PayGroupListParams(TypedDict, total=False): individual_id: str - pay_frequencies: List[str] + pay_frequencies: SequenceNotStr[str] diff --git a/src/finch/types/sandbox/connection_create_params.py b/src/finch/types/sandbox/connection_create_params.py index 61d4321e..959e4ff0 100644 --- a/src/finch/types/sandbox/connection_create_params.py +++ b/src/finch/types/sandbox/connection_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["ConnectionCreateParams"] @@ -21,4 +22,4 @@ class ConnectionCreateParams(TypedDict, total=False): will not be generated, and instead only one pay period will be created. """ - products: List[str] + products: SequenceNotStr[str] diff --git a/src/finch/types/sandbox/connections/account_create_params.py b/src/finch/types/sandbox/connections/account_create_params.py index 1cdb24eb..d0536bc7 100644 --- a/src/finch/types/sandbox/connections/account_create_params.py +++ b/src/finch/types/sandbox/connections/account_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from ...._types import SequenceNotStr + __all__ = ["AccountCreateParams"] @@ -16,7 +17,7 @@ class AccountCreateParams(TypedDict, total=False): authentication_type: Literal["credential", "api_token", "oauth", "assisted"] - products: List[str] + products: SequenceNotStr[str] """ Optional, defaults to Organization products (`company`, `directory`, `employment`, `individual`) diff --git a/tests/utils.py b/tests/utils.py index 9a6d6385..c8c239a0 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,7 +4,7 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Iterator, cast +from typing import Any, TypeVar, Iterator, Sequence, cast from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type @@ -15,6 +15,7 @@ is_list_type, is_union_type, extract_type_arg, + is_sequence_type, is_annotated_type, is_type_alias_type, ) @@ -71,6 +72,13 @@ def assert_matches_type( if is_list_type(type_): return _assert_list_type(type_, value) + if is_sequence_type(type_): + assert isinstance(value, Sequence) + inner_type = get_args(type_)[0] + for entry in value: # type: ignore + assert_type(inner_type, entry) # type: ignore + return + if origin == str: assert isinstance(value, str) elif origin == int: