Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.20.5"
".": "0.20.6"
}
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
configured_endpoints: 35
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch-a14d8915465614a275f05ccb91513576fab0525b488cb878dbe3d692f5b2349f.yml
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch-55ff507660a4f8b4a1809ca01861098c7bc72e8e6ea038fb3aa8c0a3b9a954e2.yml
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## 0.20.6 (2024-05-14)

Full Changelog: [v0.20.5...v0.20.6](https://github.com/Finch-API/finch-api-python/compare/v0.20.5...v0.20.6)

### Bug Fixes

* **api:** correct authentication methods type ([#381](https://github.com/Finch-API/finch-api-python/issues/381)) ([bcf80af](https://github.com/Finch-API/finch-api-python/commit/bcf80af518349e89c56f99ce70392e8c4ec8d6f0))


### Chores

* **internal:** bump pydantic dependency ([#379](https://github.com/Finch-API/finch-api-python/issues/379)) ([fa53eb7](https://github.com/Finch-API/finch-api-python/commit/fa53eb76a06a88d4b007116c7794c0693438f784))
* **internal:** minor updates ([#377](https://github.com/Finch-API/finch-api-python/issues/377)) ([f2f1236](https://github.com/Finch-API/finch-api-python/commit/f2f12364794b7da31f2cb80b395d36a80fa03ca3))
* **tests:** update client ID example value ([#382](https://github.com/Finch-API/finch-api-python/issues/382)) ([56b9ec4](https://github.com/Finch-API/finch-api-python/commit/56b9ec415fed15123503ce1819d996d13813bb36))

## 0.20.5 (2024-05-10)

Full Changelog: [v0.20.4...v0.20.5](https://github.com/Finch-API/finch-api-python/compare/v0.20.4...v0.20.5)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "finch-api"
version = "0.20.5"
version = "0.20.6"
description = "The official Python library for the Finch API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ pluggy==1.3.0
# via pytest
py==1.11.0
# via pytest
pydantic==2.4.2
pydantic==2.7.1
# via finch-api
pydantic-core==2.10.1
pydantic-core==2.18.2
# via pydantic
pyright==1.1.359
pytest==7.1.1
Expand Down
4 changes: 2 additions & 2 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ httpx==0.25.2
idna==3.4
# via anyio
# via httpx
pydantic==2.4.2
pydantic==2.7.1
# via finch-api
pydantic-core==2.10.1
pydantic-core==2.18.2
# via pydantic
sniffio==1.3.0
# via anyio
Expand Down
20 changes: 16 additions & 4 deletions src/finch/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
from ._constants import RAW_RESPONSE_HEADER

if TYPE_CHECKING:
from pydantic_core.core_schema import ModelField, ModelFieldsSchema
from pydantic_core.core_schema import ModelField, LiteralSchema, ModelFieldsSchema

__all__ = ["BaseModel", "GenericModel"]

Expand Down Expand Up @@ -251,7 +251,9 @@ def model_dump(
exclude_defaults: bool = False,
exclude_none: bool = False,
round_trip: bool = False,
warnings: bool = True,
warnings: bool | Literal["none", "warn", "error"] = True,
context: dict[str, Any] | None = None,
serialize_as_any: bool = False,
) -> dict[str, Any]:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump

Expand Down Expand Up @@ -279,6 +281,10 @@ def model_dump(
raise ValueError("round_trip is only supported in Pydantic v2")
if warnings != True:
raise ValueError("warnings is only supported in Pydantic v2")
if context is not None:
raise ValueError("context is only supported in Pydantic v2")
if serialize_as_any != False:
raise ValueError("serialize_as_any is only supported in Pydantic v2")
return super().dict( # pyright: ignore[reportDeprecated]
include=include,
exclude=exclude,
Expand All @@ -300,7 +306,9 @@ def model_dump_json(
exclude_defaults: bool = False,
exclude_none: bool = False,
round_trip: bool = False,
warnings: bool = True,
warnings: bool | Literal["none", "warn", "error"] = True,
context: dict[str, Any] | None = None,
serialize_as_any: bool = False,
) -> str:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json

Expand All @@ -324,6 +332,10 @@ def model_dump_json(
raise ValueError("round_trip is only supported in Pydantic v2")
if warnings != True:
raise ValueError("warnings is only supported in Pydantic v2")
if context is not None:
raise ValueError("context is only supported in Pydantic v2")
if serialize_as_any != False:
raise ValueError("serialize_as_any is only supported in Pydantic v2")
return super().json( # type: ignore[reportDeprecated]
indent=indent,
include=include,
Expand Down Expand Up @@ -550,7 +562,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any,
field_schema = field["schema"]

if field_schema["type"] == "literal":
for entry in field_schema["expected"]:
for entry in cast("LiteralSchema", field_schema)["expected"]:
if isinstance(entry, str):
mapping[entry] = variant
else:
Expand Down
2 changes: 1 addition & 1 deletion src/finch/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "finch"
__version__ = "0.20.5" # x-release-please-version
__version__ = "0.20.6" # x-release-please-version
2 changes: 2 additions & 0 deletions src/finch/types/hris/employment_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class EmploymentData(BaseModel):
last_name: Optional[str] = None
"""The legal last name of the individual."""

latest_rehire_date: Optional[str] = None

location: Optional[Location] = None

manager: Optional[Manager] = None
Expand Down
10 changes: 5 additions & 5 deletions src/finch/types/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
from .._models import BaseModel
from .shared.connection_status_type import ConnectionStatusType

__all__ = ["Introspection", "AuthenticationMethods", "AuthenticationMethodsConnectionStatus"]
__all__ = ["Introspection", "AuthenticationMethod", "AuthenticationMethodConnectionStatus"]


class AuthenticationMethodsConnectionStatus(BaseModel):
class AuthenticationMethodConnectionStatus(BaseModel):
message: Optional[str] = None

status: Optional[ConnectionStatusType] = None


class AuthenticationMethods(BaseModel):
connection_status: Optional[AuthenticationMethodsConnectionStatus] = None
class AuthenticationMethod(BaseModel):
connection_status: Optional[AuthenticationMethodConnectionStatus] = None

type: Optional[str] = None

Expand All @@ -25,7 +25,7 @@ class Introspection(BaseModel):
account_id: str
"""The Finch uuid of the account used to connect this company."""

authentication_methods: AuthenticationMethods
authentication_methods: List[AuthenticationMethod]

client_id: str
"""The client id of the application associated with the `access_token`."""
Expand Down
3 changes: 3 additions & 0 deletions src/finch/types/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ class Provider(BaseModel):
authentication_methods: Optional[List[AuthenticationMethod]] = None
"""The list of authentication methods supported by the provider."""

beta: Optional[bool] = None
"""`true` if the integration is in a beta state, `false` otherwise"""

display_name: Optional[str] = None
"""The display name of the payroll provider."""

Expand Down
4 changes: 2 additions & 2 deletions tests/api_resources/test_access_tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def test_method_create(self, client: Finch) -> None:
def test_method_create_with_all_params(self, client: Finch) -> None:
access_token = client.access_tokens.create(
code="<your_authorization_code>",
client_id="<your_client_id>",
client_id="12345678-1234-1234-1234-123456789ABC",
client_secret="<your_client_secret>",
redirect_uri="https://example.com",
)
Expand Down Expand Up @@ -73,7 +73,7 @@ async def test_method_create(self, async_client: AsyncFinch) -> None:
async def test_method_create_with_all_params(self, async_client: AsyncFinch) -> None:
access_token = await async_client.access_tokens.create(
code="<your_authorization_code>",
client_id="<your_client_id>",
client_id="12345678-1234-1234-1234-123456789ABC",
client_secret="<your_client_secret>",
redirect_uri="https://example.com",
)
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def event_loop() -> Iterator[asyncio.AbstractEventLoop]:
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")

access_token = "My Access Token"
client_id = "My Client ID"
client_id = "4ab15e51-11ad-49f4-acae-f343b7794375"
client_secret = "My Client Secret"


Expand Down
14 changes: 7 additions & 7 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
access_token = "My Access Token"
client_id = "My Client ID"
client_id = "4ab15e51-11ad-49f4-acae-f343b7794375"
client_secret = "My Client Secret"


Expand Down Expand Up @@ -73,9 +73,9 @@ def test_copy(self) -> None:
assert copied.access_token == "another My Access Token"
assert self.client.access_token == "My Access Token"

copied = self.client.copy(client_id="another My Client ID")
assert copied.client_id == "another My Client ID"
assert self.client.client_id == "My Client ID"
copied = self.client.copy(client_id="another 4ab15e51-11ad-49f4-acae-f343b7794375")
assert copied.client_id == "another 4ab15e51-11ad-49f4-acae-f343b7794375"
assert self.client.client_id == "4ab15e51-11ad-49f4-acae-f343b7794375"

copied = self.client.copy(client_secret="another My Client Secret")
assert copied.client_secret == "another My Client Secret"
Expand Down Expand Up @@ -989,9 +989,9 @@ def test_copy(self) -> None:
assert copied.access_token == "another My Access Token"
assert self.client.access_token == "My Access Token"

copied = self.client.copy(client_id="another My Client ID")
assert copied.client_id == "another My Client ID"
assert self.client.client_id == "My Client ID"
copied = self.client.copy(client_id="another 4ab15e51-11ad-49f4-acae-f343b7794375")
assert copied.client_id == "another 4ab15e51-11ad-49f4-acae-f343b7794375"
assert self.client.client_id == "4ab15e51-11ad-49f4-acae-f343b7794375"

copied = self.client.copy(client_secret="another My Client Secret")
assert copied.client_secret == "another My Client Secret"
Expand Down
8 changes: 4 additions & 4 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class NestedModel(BaseModel):

# mismatched types
m = NestedModel.construct(nested="hello!")
assert m.nested == "hello!"
assert cast(Any, m.nested) == "hello!"


def test_optional_nested_model() -> None:
Expand All @@ -48,7 +48,7 @@ class NestedModel(BaseModel):
# mismatched types
m3 = NestedModel.construct(nested={"foo"})
assert isinstance(cast(Any, m3.nested), set)
assert m3.nested == {"foo"}
assert cast(Any, m3.nested) == {"foo"}


def test_list_nested_model() -> None:
Expand Down Expand Up @@ -323,7 +323,7 @@ class Model(BaseModel):
assert len(m.items) == 2
assert isinstance(m.items[0], Submodel1)
assert m.items[0].level == -1
assert m.items[1] == 156
assert cast(Any, m.items[1]) == 156


def test_union_of_lists() -> None:
Expand Down Expand Up @@ -355,7 +355,7 @@ class Model(BaseModel):
assert len(m.items) == 2
assert isinstance(m.items[0], SubModel1)
assert m.items[0].level == -1
assert m.items[1] == 156
assert cast(Any, m.items[1]) == 156


def test_dict_of_union() -> None:
Expand Down
22 changes: 12 additions & 10 deletions tests/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,20 +260,22 @@ class MyModel(BaseModel):
@parametrize
@pytest.mark.asyncio
async def test_pydantic_model_to_dictionary(use_async: bool) -> None:
assert await transform(MyModel(foo="hi!"), Any, use_async) == {"foo": "hi!"}
assert await transform(MyModel.construct(foo="hi!"), Any, use_async) == {"foo": "hi!"}
assert cast(Any, await transform(MyModel(foo="hi!"), Any, use_async)) == {"foo": "hi!"}
assert cast(Any, await transform(MyModel.construct(foo="hi!"), Any, use_async)) == {"foo": "hi!"}


@parametrize
@pytest.mark.asyncio
async def test_pydantic_empty_model(use_async: bool) -> None:
assert await transform(MyModel.construct(), Any, use_async) == {}
assert cast(Any, await transform(MyModel.construct(), Any, use_async)) == {}


@parametrize
@pytest.mark.asyncio
async def test_pydantic_unknown_field(use_async: bool) -> None:
assert await transform(MyModel.construct(my_untyped_field=True), Any, use_async) == {"my_untyped_field": True}
assert cast(Any, await transform(MyModel.construct(my_untyped_field=True), Any, use_async)) == {
"my_untyped_field": True
}


@parametrize
Expand All @@ -285,7 +287,7 @@ async def test_pydantic_mismatched_types(use_async: bool) -> None:
params = await transform(model, Any, use_async)
else:
params = await transform(model, Any, use_async)
assert params == {"foo": True}
assert cast(Any, params) == {"foo": True}


@parametrize
Expand All @@ -297,7 +299,7 @@ async def test_pydantic_mismatched_object_type(use_async: bool) -> None:
params = await transform(model, Any, use_async)
else:
params = await transform(model, Any, use_async)
assert params == {"foo": {"hello": "world"}}
assert cast(Any, params) == {"foo": {"hello": "world"}}


class ModelNestedObjects(BaseModel):
Expand All @@ -309,7 +311,7 @@ class ModelNestedObjects(BaseModel):
async def test_pydantic_nested_objects(use_async: bool) -> None:
model = ModelNestedObjects.construct(nested={"foo": "stainless"})
assert isinstance(model.nested, MyModel)
assert await transform(model, Any, use_async) == {"nested": {"foo": "stainless"}}
assert cast(Any, await transform(model, Any, use_async)) == {"nested": {"foo": "stainless"}}


class ModelWithDefaultField(BaseModel):
Expand All @@ -325,19 +327,19 @@ async def test_pydantic_default_field(use_async: bool) -> None:
model = ModelWithDefaultField.construct()
assert model.with_none_default is None
assert model.with_str_default == "foo"
assert await transform(model, Any, use_async) == {}
assert cast(Any, await transform(model, Any, use_async)) == {}

# should be included when the default value is explicitly given
model = ModelWithDefaultField.construct(with_none_default=None, with_str_default="foo")
assert model.with_none_default is None
assert model.with_str_default == "foo"
assert await transform(model, Any, use_async) == {"with_none_default": None, "with_str_default": "foo"}
assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": None, "with_str_default": "foo"}

# should be included when a non-default value is explicitly given
model = ModelWithDefaultField.construct(with_none_default="bar", with_str_default="baz")
assert model.with_none_default == "bar"
assert model.with_str_default == "baz"
assert await transform(model, Any, use_async) == {"with_none_default": "bar", "with_str_default": "baz"}
assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": "bar", "with_str_default": "baz"}


class TypedDictIterableUnion(TypedDict):
Expand Down