From 42de23d5c7a3b9253396b94af7884e7a9300b841 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Wed, 29 Nov 2023 05:56:19 -0500
Subject: [PATCH 01/26] chore(internal): update lock file (#201)
---
requirements-dev.lock | 1 -
1 file changed, 1 deletion(-)
diff --git a/requirements-dev.lock b/requirements-dev.lock
index fd275d2e..e7a2e23a 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -41,7 +41,6 @@ pyright==1.1.332
pytest==7.1.1
pytest-asyncio==0.21.1
python-dateutil==2.8.2
-pytz==2023.3.post1
respx==0.19.2
rfc3986==1.5.0
ruff==0.0.282
From 2049c50e723ec6ec4b4d46a18fa87800a58d581a Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Wed, 29 Nov 2023 06:38:32 -0500
Subject: [PATCH 02/26] chore(internal): updates to proxy helper (#202)
---
src/finch/_utils/_proxy.py | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/src/finch/_utils/_proxy.py b/src/finch/_utils/_proxy.py
index aa934a3f..3c9e790a 100644
--- a/src/finch/_utils/_proxy.py
+++ b/src/finch/_utils/_proxy.py
@@ -18,25 +18,43 @@ class LazyProxy(Generic[T], ABC):
def __init__(self) -> None:
self.__proxied: T | None = None
+ # Note: we have to special case proxies that themselves return proxies
+ # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz`
+
def __getattr__(self, attr: str) -> object:
- return getattr(self.__get_proxied__(), attr)
+ proxied = self.__get_proxied__()
+ if isinstance(proxied, LazyProxy):
+ return proxied # pyright: ignore
+ return getattr(proxied, attr)
@override
def __repr__(self) -> str:
+ proxied = self.__get_proxied__()
+ if isinstance(proxied, LazyProxy):
+ return proxied.__class__.__name__
return repr(self.__get_proxied__())
@override
def __str__(self) -> str:
- return str(self.__get_proxied__())
+ proxied = self.__get_proxied__()
+ if isinstance(proxied, LazyProxy):
+ return proxied.__class__.__name__
+ return str(proxied)
@override
def __dir__(self) -> Iterable[str]:
- return self.__get_proxied__().__dir__()
+ proxied = self.__get_proxied__()
+ if isinstance(proxied, LazyProxy):
+ return []
+ return proxied.__dir__()
@property # type: ignore
@override
def __class__(self) -> type:
- return self.__get_proxied__().__class__
+ proxied = self.__get_proxied__()
+ if issubclass(type(proxied), LazyProxy):
+ return type(proxied)
+ return proxied.__class__
def __get_proxied__(self) -> T:
if not self.should_cache:
From b5b9f79c19e846e2e8fc3fd1faf905a65a6aa7c4 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Wed, 29 Nov 2023 07:24:27 -0500
Subject: [PATCH 03/26] chore(internal): add tests for proxy change (#203)
---
tests/test_utils/test_proxy.py | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 tests/test_utils/test_proxy.py
diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py
new file mode 100644
index 00000000..4a7336a8
--- /dev/null
+++ b/tests/test_utils/test_proxy.py
@@ -0,0 +1,23 @@
+import operator
+from typing import Any
+from typing_extensions import override
+
+from finch._utils import LazyProxy
+
+
+class RecursiveLazyProxy(LazyProxy[Any]):
+ @override
+ def __load__(self) -> Any:
+ return self
+
+ def __call__(self, *_args: Any, **_kwds: Any) -> Any:
+ raise RuntimeError("This should never be called!")
+
+
+def test_recursive_proxy() -> None:
+ proxy = RecursiveLazyProxy()
+ assert repr(proxy) == "RecursiveLazyProxy"
+ assert str(proxy) == "RecursiveLazyProxy"
+ assert dir(proxy) == []
+ assert getattr(type(proxy), "__name__") == "RecursiveLazyProxy"
+ assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy"
From 0659932aaaa69850982e6acbe076a4af7980efcd Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Wed, 29 Nov 2023 19:02:23 -0500
Subject: [PATCH 04/26] fix(client): ensure retried requests are closed (#204)
---
src/finch/_base_client.py | 100 ++++++++++++++++++++++++++++++--------
src/finch/_constants.py | 1 +
tests/test_client.py | 53 +++++++++++++++++++-
3 files changed, 133 insertions(+), 21 deletions(-)
diff --git a/src/finch/_base_client.py b/src/finch/_base_client.py
index a168301f..89d9ce48 100644
--- a/src/finch/_base_client.py
+++ b/src/finch/_base_client.py
@@ -72,6 +72,7 @@
DEFAULT_TIMEOUT,
DEFAULT_MAX_RETRIES,
RAW_RESPONSE_HEADER,
+ STREAMED_RAW_RESPONSE_HEADER,
)
from ._streaming import Stream, AsyncStream
from ._exceptions import (
@@ -363,14 +364,21 @@ def _make_status_error_from_response(
self,
response: httpx.Response,
) -> APIStatusError:
- err_text = response.text.strip()
- body = err_text
+ if response.is_closed and not response.is_stream_consumed:
+ # We can't read the response body as it has been closed
+ # before it was read. This can happen if an event hook
+ # raises a status error.
+ body = None
+ err_msg = f"Error code: {response.status_code}"
+ else:
+ err_text = response.text.strip()
+ body = err_text
- try:
- body = json.loads(err_text)
- err_msg = f"Error code: {response.status_code} - {body}"
- except Exception:
- err_msg = err_text or f"Error code: {response.status_code}"
+ try:
+ body = json.loads(err_text)
+ err_msg = f"Error code: {response.status_code} - {body}"
+ except Exception:
+ err_msg = err_text or f"Error code: {response.status_code}"
return self._make_status_error(err_msg, body=body, response=response)
@@ -534,6 +542,12 @@ def _process_response_data(
except pydantic.ValidationError as err:
raise APIResponseValidationError(response=response, body=data) from err
+ def _should_stream_response_body(self, *, request: httpx.Request) -> bool:
+ if request.headers.get(STREAMED_RAW_RESPONSE_HEADER) == "true":
+ return True
+
+ return False
+
@property
def qs(self) -> Querystring:
return Querystring()
@@ -606,7 +620,7 @@ def _calculate_retry_timeout(
if response_headers is not None:
retry_header = response_headers.get("retry-after")
try:
- retry_after = int(retry_header)
+ retry_after = float(retry_header)
except Exception:
retry_date_tuple = email.utils.parsedate_tz(retry_header)
if retry_date_tuple is None:
@@ -862,14 +876,21 @@ def _request(
request = self._build_request(options)
self._prepare_request(request)
+ response = None
+
try:
- response = self._client.send(request, auth=self.custom_auth, stream=stream)
+ response = self._client.send(
+ request,
+ auth=self.custom_auth,
+ stream=stream or self._should_stream_response_body(request=request),
+ )
log.debug(
'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
)
response.raise_for_status()
except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
if retries > 0 and self._should_retry(err.response):
+ err.response.close()
return self._retry_request(
options,
cast_to,
@@ -881,9 +902,14 @@ def _request(
# If the response is streamed then we need to explicitly read the response
# to completion before attempting to access the response text.
- err.response.read()
+ if not err.response.is_closed:
+ err.response.read()
+
raise self._make_status_error_from_response(err.response) from None
except httpx.TimeoutException as err:
+ if response is not None:
+ response.close()
+
if retries > 0:
return self._retry_request(
options,
@@ -891,9 +917,14 @@ def _request(
retries,
stream=stream,
stream_cls=stream_cls,
+ response_headers=response.headers if response is not None else None,
)
+
raise APITimeoutError(request=request) from err
except Exception as err:
+ if response is not None:
+ response.close()
+
if retries > 0:
return self._retry_request(
options,
@@ -901,7 +932,9 @@ def _request(
retries,
stream=stream,
stream_cls=stream_cls,
+ response_headers=response.headers if response is not None else None,
)
+
raise APIConnectionError(request=request) from err
return self._process_response(
@@ -917,7 +950,7 @@ def _retry_request(
options: FinalRequestOptions,
cast_to: Type[ResponseT],
remaining_retries: int,
- response_headers: Optional[httpx.Headers] = None,
+ response_headers: httpx.Headers | None,
*,
stream: bool,
stream_cls: type[_StreamT] | None,
@@ -1303,14 +1336,21 @@ async def _request(
request = self._build_request(options)
await self._prepare_request(request)
+ response = None
+
try:
- response = await self._client.send(request, auth=self.custom_auth, stream=stream)
+ response = await self._client.send(
+ request,
+ auth=self.custom_auth,
+ stream=stream or self._should_stream_response_body(request=request),
+ )
log.debug(
'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
)
response.raise_for_status()
except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
if retries > 0 and self._should_retry(err.response):
+ await err.response.aclose()
return await self._retry_request(
options,
cast_to,
@@ -1322,19 +1362,39 @@ async def _request(
# If the response is streamed then we need to explicitly read the response
# to completion before attempting to access the response text.
- await err.response.aread()
+ if not err.response.is_closed:
+ await err.response.aread()
+
raise self._make_status_error_from_response(err.response) from None
- except httpx.ConnectTimeout as err:
- if retries > 0:
- return await self._retry_request(options, cast_to, retries, stream=stream, stream_cls=stream_cls)
- raise APITimeoutError(request=request) from err
except httpx.TimeoutException as err:
+ if response is not None:
+ await response.aclose()
+
if retries > 0:
- return await self._retry_request(options, cast_to, retries, stream=stream, stream_cls=stream_cls)
+ return await self._retry_request(
+ options,
+ cast_to,
+ retries,
+ stream=stream,
+ stream_cls=stream_cls,
+ response_headers=response.headers if response is not None else None,
+ )
+
raise APITimeoutError(request=request) from err
except Exception as err:
+ if response is not None:
+ await response.aclose()
+
if retries > 0:
- return await self._retry_request(options, cast_to, retries, stream=stream, stream_cls=stream_cls)
+ return await self._retry_request(
+ options,
+ cast_to,
+ retries,
+ stream=stream,
+ stream_cls=stream_cls,
+ response_headers=response.headers if response is not None else None,
+ )
+
raise APIConnectionError(request=request) from err
return self._process_response(
@@ -1350,7 +1410,7 @@ async def _retry_request(
options: FinalRequestOptions,
cast_to: Type[ResponseT],
remaining_retries: int,
- response_headers: Optional[httpx.Headers] = None,
+ response_headers: httpx.Headers | None,
*,
stream: bool,
stream_cls: type[_AsyncStreamT] | None,
diff --git a/src/finch/_constants.py b/src/finch/_constants.py
index 0c3f31df..39b46eb0 100644
--- a/src/finch/_constants.py
+++ b/src/finch/_constants.py
@@ -3,6 +3,7 @@
import httpx
RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response"
+STREAMED_RAW_RESPONSE_HEADER = "X-Stainless-Streamed-Raw-Response"
# default timeout is 1 minute
DEFAULT_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0)
diff --git a/tests/test_client.py b/tests/test_client.py
index 5c5b16b1..a95af2f6 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -18,7 +18,7 @@
from finch._types import Omit
from finch._client import Finch, AsyncFinch
from finch._models import BaseModel, FinalRequestOptions
-from finch._exceptions import APIResponseValidationError
+from finch._exceptions import APIStatusError, APIResponseValidationError
from finch._base_client import (
DEFAULT_TIMEOUT,
HTTPX_DEFAULT_TIMEOUT,
@@ -704,6 +704,31 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str
calculated = client._calculate_retry_timeout(remaining_retries, options, headers)
assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType]
+ @pytest.mark.respx(base_url=base_url)
+ def test_status_error_within_httpx(self, respx_mock: MockRouter) -> None:
+ respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+
+ def on_response(response: httpx.Response) -> None:
+ raise httpx.HTTPStatusError(
+ "Simulating an error inside httpx",
+ response=response,
+ request=response.request,
+ )
+
+ client = Finch(
+ base_url=base_url,
+ access_token=access_token,
+ _strict_response_validation=True,
+ http_client=httpx.Client(
+ event_hooks={
+ "response": [on_response],
+ }
+ ),
+ max_retries=0,
+ )
+ with pytest.raises(APIStatusError):
+ client.post("/foo", cast_to=httpx.Response)
+
class TestAsyncFinch:
client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
@@ -1377,3 +1402,29 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte
options = FinalRequestOptions(method="get", url="/foo", max_retries=3)
calculated = client._calculate_retry_timeout(remaining_retries, options, headers)
assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType]
+
+ @pytest.mark.respx(base_url=base_url)
+ @pytest.mark.asyncio
+ async def test_status_error_within_httpx(self, respx_mock: MockRouter) -> None:
+ respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
+
+ def on_response(response: httpx.Response) -> None:
+ raise httpx.HTTPStatusError(
+ "Simulating an error inside httpx",
+ response=response,
+ request=response.request,
+ )
+
+ client = AsyncFinch(
+ base_url=base_url,
+ access_token=access_token,
+ _strict_response_validation=True,
+ http_client=httpx.AsyncClient(
+ event_hooks={
+ "response": [on_response],
+ }
+ ),
+ max_retries=0,
+ )
+ with pytest.raises(APIStatusError):
+ await client.post("/foo", cast_to=httpx.Response)
From 4ff1a6b04ba8e3301ac6ff4a612bb8aab801abd0 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Thu, 30 Nov 2023 08:20:28 -0500
Subject: [PATCH 05/26] docs(readme): update example snippets (#205)
---
src/finch/types/hris/benfit_contribution.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/finch/types/hris/benfit_contribution.py b/src/finch/types/hris/benfit_contribution.py
index 522d5602..676c3b8e 100644
--- a/src/finch/types/hris/benfit_contribution.py
+++ b/src/finch/types/hris/benfit_contribution.py
@@ -1,6 +1,5 @@
# File generated from our OpenAPI spec by Stainless.
-
from .benefit_contribution import BenefitContribution
BenfitContribution = BenefitContribution
From 7c920a33c103fadee08cd784f5d028f2ab19411f Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Thu, 30 Nov 2023 12:52:08 -0500
Subject: [PATCH 06/26] chore(internal): replace string concatenation with
f-strings (#206)
---
src/finch/_utils/_utils.py | 2 +-
tests/test_required_args.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/finch/_utils/_utils.py b/src/finch/_utils/_utils.py
index d2bfc91a..83f88cc3 100644
--- a/src/finch/_utils/_utils.py
+++ b/src/finch/_utils/_utils.py
@@ -230,7 +230,7 @@ def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> s
def quote(string: str) -> str:
"""Add single quotation marks around the given string. Does *not* do any escaping."""
- return "'" + string + "'"
+ return f"'{string}'"
def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]:
diff --git a/tests/test_required_args.py b/tests/test_required_args.py
index e839289d..38007450 100644
--- a/tests/test_required_args.py
+++ b/tests/test_required_args.py
@@ -43,7 +43,7 @@ def foo(*, a: str | None = None) -> str | None:
def test_multiple_params() -> None:
@required_args(["a", "b", "c"])
def foo(a: str = "", *, b: str = "", c: str = "") -> str | None:
- return a + " " + b + " " + c
+ return f"{a} {b} {c}"
assert foo(a="a", b="b", c="c") == "a b c"
From 5e04fa773d4603d0be73aa67268b17fdc4f6fed2 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Fri, 1 Dec 2023 12:53:34 -0500
Subject: [PATCH 07/26] fix(client): correct base_url setter implementation
(#207)
---
src/finch/_base_client.py | 2 +-
tests/test_client.py | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/finch/_base_client.py b/src/finch/_base_client.py
index 89d9ce48..2e5678e8 100644
--- a/src/finch/_base_client.py
+++ b/src/finch/_base_client.py
@@ -592,7 +592,7 @@ def base_url(self) -> URL:
@base_url.setter
def base_url(self, url: URL | str) -> None:
- self._client.base_url = url if isinstance(url, URL) else URL(url)
+ self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url))
@lru_cache(maxsize=None)
def platform_headers(self) -> Dict[str, str]:
diff --git a/tests/test_client.py b/tests/test_client.py
index a95af2f6..55502d8e 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -441,6 +441,16 @@ class Model(BaseModel):
assert isinstance(response, Model)
assert response.foo == 2
+ def test_base_url_setter(self) -> None:
+ client = Finch(
+ base_url="https://example.com/from_init", access_token=access_token, _strict_response_validation=True
+ )
+ assert client.base_url == "https://example.com/from_init/"
+
+ client.base_url = "https://example.com/from_setter" # type: ignore[assignment]
+
+ assert client.base_url == "https://example.com/from_setter/"
+
def test_base_url_env(self) -> None:
with update_env(FINCH_BASE_URL="http://localhost:5000/from/env"):
client = Finch(access_token=access_token, _strict_response_validation=True)
@@ -1135,6 +1145,16 @@ class Model(BaseModel):
assert isinstance(response, Model)
assert response.foo == 2
+ def test_base_url_setter(self) -> None:
+ client = AsyncFinch(
+ base_url="https://example.com/from_init", access_token=access_token, _strict_response_validation=True
+ )
+ assert client.base_url == "https://example.com/from_init/"
+
+ client.base_url = "https://example.com/from_setter" # type: ignore[assignment]
+
+ assert client.base_url == "https://example.com/from_setter/"
+
def test_base_url_env(self) -> None:
with update_env(FINCH_BASE_URL="http://localhost:5000/from/env"):
client = AsyncFinch(access_token=access_token, _strict_response_validation=True)
From e1ed4a53591362f5e2579e301b43529b64f2fc8b Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Mon, 4 Dec 2023 05:27:09 -0500
Subject: [PATCH 08/26] chore(package): lift anyio v4 restriction (#208)
---
pyproject.toml | 4 ++--
requirements-dev.lock | 12 ++++++------
requirements.lock | 9 ++++-----
tests/test_client.py | 30 +++++++++++++++++++-----------
4 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 7b3b5304..b831f420 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ dependencies = [
"httpx>=0.23.0, <1",
"pydantic>=1.9.0, <3",
"typing-extensions>=4.5, <5",
- "anyio>=3.5.0, <4",
+ "anyio>=3.5.0, <5",
"distro>=1.7.0, <2",
"sniffio",
@@ -49,7 +49,7 @@ dev-dependencies = [
"pyright==1.1.332",
"mypy==1.7.1",
"black==23.3.0",
- "respx==0.19.2",
+ "respx==0.20.2",
"pytest==7.1.1",
"pytest-asyncio==0.21.1",
"ruff==0.0.282",
diff --git a/requirements-dev.lock b/requirements-dev.lock
index e7a2e23a..ce154682 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -8,7 +8,7 @@
-e file:.
annotated-types==0.6.0
-anyio==3.7.1
+anyio==4.1.0
argcomplete==3.1.2
attrs==23.1.0
black==23.3.0
@@ -20,9 +20,9 @@ distlib==0.3.7
distro==1.8.0
exceptiongroup==1.1.3
filelock==3.12.4
-h11==0.12.0
-httpcore==0.15.0
-httpx==0.23.0
+h11==0.14.0
+httpcore==1.0.2
+httpx==0.25.2
idna==3.4
iniconfig==2.0.0
isort==5.10.1
@@ -41,8 +41,8 @@ pyright==1.1.332
pytest==7.1.1
pytest-asyncio==0.21.1
python-dateutil==2.8.2
-respx==0.19.2
-rfc3986==1.5.0
+pytz==2023.3.post1
+respx==0.20.2
ruff==0.0.282
six==1.16.0
sniffio==1.3.0
diff --git a/requirements.lock b/requirements.lock
index 0c8c2c2e..2022a5c5 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -8,16 +8,15 @@
-e file:.
annotated-types==0.6.0
-anyio==3.7.1
+anyio==4.1.0
certifi==2023.7.22
distro==1.8.0
exceptiongroup==1.1.3
-h11==0.12.0
-httpcore==0.15.0
-httpx==0.23.0
+h11==0.14.0
+httpcore==1.0.2
+httpx==0.25.2
idna==3.4
pydantic==2.4.2
pydantic-core==2.10.1
-rfc3986==1.5.0
sniffio==1.3.0
typing-extensions==4.8.0
diff --git a/tests/test_client.py b/tests/test_client.py
index 55502d8e..a37278e9 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -6,7 +6,7 @@
import json
import asyncio
import inspect
-from typing import Any, Dict, Union, cast
+from typing import Any, Union, cast
from unittest import mock
import httpx
@@ -353,7 +353,7 @@ def test_request_extra_query(self) -> None:
),
),
)
- params = cast(Dict[str, str], dict(request.url.params))
+ params = dict(request.url.params)
assert params == {"my_query_param": "Foo"}
# if both `query` and `extra_query` are given, they are merged
@@ -367,7 +367,7 @@ def test_request_extra_query(self) -> None:
),
),
)
- params = cast(Dict[str, str], dict(request.url.params))
+ params = dict(request.url.params)
assert params == {"bar": "1", "foo": "2"}
# `extra_query` takes priority over `query` when keys clash
@@ -381,7 +381,7 @@ def test_request_extra_query(self) -> None:
),
),
)
- params = cast(Dict[str, str], dict(request.url.params))
+ params = dict(request.url.params)
assert params == {"foo": "2"}
@pytest.mark.respx(base_url=base_url)
@@ -542,7 +542,9 @@ def test_transport_option_is_deprecated(self) -> None:
DeprecationWarning,
match="The `transport` argument is deprecated. The `http_client` argument should be passed instead",
):
- transport = httpx.MockTransport(lambda: None)
+ transport = httpx.MockTransport(
+ lambda: None, # type: ignore
+ )
client = Finch(
base_url=base_url, access_token=access_token, _strict_response_validation=True, transport=transport
@@ -558,7 +560,9 @@ def test_transport_option_mutually_exclusive_with_http_client(self) -> None:
base_url=base_url,
access_token=access_token,
_strict_response_validation=True,
- transport=httpx.MockTransport(lambda: None),
+ transport=httpx.MockTransport(
+ lambda: None, # type: ignore
+ ),
http_client=http_client,
)
@@ -1057,7 +1061,7 @@ def test_request_extra_query(self) -> None:
),
),
)
- params = cast(Dict[str, str], dict(request.url.params))
+ params = dict(request.url.params)
assert params == {"my_query_param": "Foo"}
# if both `query` and `extra_query` are given, they are merged
@@ -1071,7 +1075,7 @@ def test_request_extra_query(self) -> None:
),
),
)
- params = cast(Dict[str, str], dict(request.url.params))
+ params = dict(request.url.params)
assert params == {"bar": "1", "foo": "2"}
# `extra_query` takes priority over `query` when keys clash
@@ -1085,7 +1089,7 @@ def test_request_extra_query(self) -> None:
),
),
)
- params = cast(Dict[str, str], dict(request.url.params))
+ params = dict(request.url.params)
assert params == {"foo": "2"}
@pytest.mark.respx(base_url=base_url)
@@ -1246,7 +1250,9 @@ def test_transport_option_is_deprecated(self) -> None:
DeprecationWarning,
match="The `transport` argument is deprecated. The `http_client` argument should be passed instead",
):
- transport = httpx.MockTransport(lambda: None)
+ transport = httpx.MockTransport(
+ lambda: None, # type: ignore
+ )
client = AsyncFinch(
base_url=base_url, access_token=access_token, _strict_response_validation=True, transport=transport
@@ -1262,7 +1268,9 @@ async def test_transport_option_mutually_exclusive_with_http_client(self) -> Non
base_url=base_url,
access_token=access_token,
_strict_response_validation=True,
- transport=httpx.MockTransport(lambda: None),
+ transport=httpx.MockTransport(
+ lambda: None, # type: ignore
+ ),
http_client=http_client,
)
From 6b8c8a39e528e5fef8b4ad2c33ab85548803fb40 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Mon, 4 Dec 2023 05:45:09 -0500
Subject: [PATCH 09/26] ci: ensure PR titles use conventional commits (#209)
---
.github/workflows/lint-pr.yml | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 .github/workflows/lint-pr.yml
diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml
new file mode 100644
index 00000000..82ee9e18
--- /dev/null
+++ b/.github/workflows/lint-pr.yml
@@ -0,0 +1,21 @@
+name: "Lint PR"
+
+on:
+ pull_request_target:
+ types:
+ - opened
+ - edited
+ - synchronize
+
+permissions:
+ pull-requests: read
+
+jobs:
+ pr_title:
+ name: Validate PR title
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/main' && github.repository == 'Finch-API/finch-api-python'
+ steps:
+ - uses: amannn/action-semantic-pull-request@v5
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
From cd3cc6febbb46537d6694303c52fbfa266e762cd Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Mon, 4 Dec 2023 13:27:06 -0500
Subject: [PATCH 10/26] feat(api): add `/jobs` endpoints (#210)
---
.stats.yml | 2 +-
api.md | 32 +-
src/finch/_client.py | 6 +
src/finch/pagination.py | 62 +++-
src/finch/resources/__init__.py | 5 +
src/finch/resources/jobs/__init__.py | 30 ++
src/finch/resources/jobs/automated.py | 318 ++++++++++++++++++
src/finch/resources/jobs/jobs.py | 60 ++++
src/finch/resources/jobs/manual.py | 114 +++++++
src/finch/types/__init__.py | 2 +-
.../types/hris/pay_statement_response_body.py | 2 +-
src/finch/types/jobs/__init__.py | 11 +
src/finch/types/jobs/automated_async_job.py | 42 +++
.../types/jobs/automated_create_params.py | 12 +
.../types/jobs/automated_create_response.py | 19 ++
src/finch/types/jobs/automated_list_params.py | 15 +
src/finch/types/jobs/manual_async_job.py | 17 +
src/finch/types/shared/__init__.py | 1 +
src/finch/types/{ => shared}/paging.py | 2 +-
src/finch/types/shared_params/__init__.py | 1 +
src/finch/types/shared_params/paging.py | 15 +
tests/api_resources/jobs/__init__.py | 1 +
tests/api_resources/jobs/test_automated.py | 132 ++++++++
tests/api_resources/jobs/test_manual.py | 59 ++++
24 files changed, 953 insertions(+), 7 deletions(-)
create mode 100644 src/finch/resources/jobs/__init__.py
create mode 100644 src/finch/resources/jobs/automated.py
create mode 100644 src/finch/resources/jobs/jobs.py
create mode 100644 src/finch/resources/jobs/manual.py
create mode 100644 src/finch/types/jobs/__init__.py
create mode 100644 src/finch/types/jobs/automated_async_job.py
create mode 100644 src/finch/types/jobs/automated_create_params.py
create mode 100644 src/finch/types/jobs/automated_create_response.py
create mode 100644 src/finch/types/jobs/automated_list_params.py
create mode 100644 src/finch/types/jobs/manual_async_job.py
rename src/finch/types/{ => shared}/paging.py (91%)
create mode 100644 src/finch/types/shared_params/paging.py
create mode 100644 tests/api_resources/jobs/__init__.py
create mode 100644 tests/api_resources/jobs/test_automated.py
create mode 100644 tests/api_resources/jobs/test_manual.py
diff --git a/.stats.yml b/.stats.yml
index a78b7ab0..c125dfb2 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 19
+configured_endpoints: 23
diff --git a/api.md b/api.md
index 0fb9d472..05326915 100644
--- a/api.md
+++ b/api.md
@@ -1,7 +1,7 @@
# Shared Types
```python
-from finch.types import OperationSupport, OperationSupportMatrix
+from finch.types import OperationSupport, OperationSupportMatrix, Paging
```
# Finch
@@ -16,7 +16,7 @@ Methods:
Types:
```python
-from finch.types import Income, Location, Money, Paging
+from finch.types import Income, Location, Money
```
## CompanyResource
@@ -186,3 +186,31 @@ from finch.types import RequestForwardingForwardResponse
Methods:
- client.request_forwarding.forward(\*\*params) -> RequestForwardingForwardResponse
+
+# Jobs
+
+## Automated
+
+Types:
+
+```python
+from finch.types.jobs import AutomatedAsyncJob, AutomatedCreateResponse
+```
+
+Methods:
+
+- client.jobs.automated.create(\*\*params) -> AutomatedCreateResponse
+- client.jobs.automated.retrieve(job_id) -> AutomatedAsyncJob
+- client.jobs.automated.list(\*\*params) -> SyncPage[AutomatedAsyncJob]
+
+## Manual
+
+Types:
+
+```python
+from finch.types.jobs import ManualAsyncJob
+```
+
+Methods:
+
+- client.jobs.manual.retrieve(job_id) -> ManualAsyncJob
diff --git a/src/finch/_client.py b/src/finch/_client.py
index d5579f9f..149406a0 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -53,6 +53,7 @@ class Finch(SyncAPIClient):
account: resources.Account
webhooks: resources.Webhooks
request_forwarding: resources.RequestForwarding
+ jobs: resources.Jobs
with_raw_response: FinchWithRawResponse
# client options
@@ -136,6 +137,7 @@ def __init__(
self.account = resources.Account(self)
self.webhooks = resources.Webhooks(self)
self.request_forwarding = resources.RequestForwarding(self)
+ self.jobs = resources.Jobs(self)
self.with_raw_response = FinchWithRawResponse(self)
@property
@@ -357,6 +359,7 @@ class AsyncFinch(AsyncAPIClient):
account: resources.AsyncAccount
webhooks: resources.AsyncWebhooks
request_forwarding: resources.AsyncRequestForwarding
+ jobs: resources.AsyncJobs
with_raw_response: AsyncFinchWithRawResponse
# client options
@@ -440,6 +443,7 @@ def __init__(
self.account = resources.AsyncAccount(self)
self.webhooks = resources.AsyncWebhooks(self)
self.request_forwarding = resources.AsyncRequestForwarding(self)
+ self.jobs = resources.AsyncJobs(self)
self.with_raw_response = AsyncFinchWithRawResponse(self)
@property
@@ -664,6 +668,7 @@ def __init__(self, client: Finch) -> None:
self.providers = resources.ProvidersWithRawResponse(client.providers)
self.account = resources.AccountWithRawResponse(client.account)
self.request_forwarding = resources.RequestForwardingWithRawResponse(client.request_forwarding)
+ self.jobs = resources.JobsWithRawResponse(client.jobs)
class AsyncFinchWithRawResponse:
@@ -672,6 +677,7 @@ def __init__(self, client: AsyncFinch) -> None:
self.providers = resources.AsyncProvidersWithRawResponse(client.providers)
self.account = resources.AsyncAccountWithRawResponse(client.account)
self.request_forwarding = resources.AsyncRequestForwardingWithRawResponse(client.request_forwarding)
+ self.jobs = resources.AsyncJobsWithRawResponse(client.jobs)
Client = Finch
diff --git a/src/finch/pagination.py b/src/finch/pagination.py
index 3cb9ed96..38caea48 100644
--- a/src/finch/pagination.py
+++ b/src/finch/pagination.py
@@ -5,11 +5,11 @@
from httpx import Response
-from .types import Paging
from ._types import ModelT
from ._utils import is_mapping
from ._models import BaseModel
from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage
+from .types.shared import Paging
__all__ = [
"SyncSinglePage",
@@ -18,6 +18,8 @@
"AsyncResponsesPage",
"SyncIndividualsPage",
"AsyncIndividualsPage",
+ "SyncPage",
+ "AsyncPage",
]
_BaseModelT = TypeVar("_BaseModelT", bound=BaseModel)
@@ -161,3 +163,61 @@ def next_page_info(self) -> Optional[PageInfo]:
return PageInfo(params={"offset": current_count})
return None
+
+
+PagePaging = Paging
+"""This is deprecated, Paging should be used instead"""
+
+
+class SyncPage(BaseSyncPage[ModelT], BasePage[ModelT], Generic[ModelT]):
+ paging: Paging
+ data: List[ModelT]
+
+ @override
+ def _get_page_items(self) -> List[ModelT]:
+ return self.data
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ offset = self.paging.offset
+ if offset is None:
+ return None
+
+ length = len(self.data)
+ current_count = offset + length
+
+ total_count = self.paging.count
+ if total_count is None:
+ return None
+
+ if current_count < total_count:
+ return PageInfo(params={"offset": current_count})
+
+ return None
+
+
+class AsyncPage(BaseAsyncPage[ModelT], BasePage[ModelT], Generic[ModelT]):
+ paging: Paging
+ data: List[ModelT]
+
+ @override
+ def _get_page_items(self) -> List[ModelT]:
+ return self.data
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ offset = self.paging.offset
+ if offset is None:
+ return None
+
+ length = len(self.data)
+ current_count = offset + length
+
+ total_count = self.paging.count
+ if total_count is None:
+ return None
+
+ if current_count < total_count:
+ return PageInfo(params={"offset": current_count})
+
+ return None
diff --git a/src/finch/resources/__init__.py b/src/finch/resources/__init__.py
index b87ddc17..dcab5333 100644
--- a/src/finch/resources/__init__.py
+++ b/src/finch/resources/__init__.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless.
from .hris import HRIS, AsyncHRIS, HRISWithRawResponse, AsyncHRISWithRawResponse
+from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse
from .account import (
Account,
AsyncAccount,
@@ -40,4 +41,8 @@
"AsyncRequestForwarding",
"RequestForwardingWithRawResponse",
"AsyncRequestForwardingWithRawResponse",
+ "Jobs",
+ "AsyncJobs",
+ "JobsWithRawResponse",
+ "AsyncJobsWithRawResponse",
]
diff --git a/src/finch/resources/jobs/__init__.py b/src/finch/resources/jobs/__init__.py
new file mode 100644
index 00000000..f1f7692d
--- /dev/null
+++ b/src/finch/resources/jobs/__init__.py
@@ -0,0 +1,30 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse
+from .manual import (
+ Manual,
+ AsyncManual,
+ ManualWithRawResponse,
+ AsyncManualWithRawResponse,
+)
+from .automated import (
+ Automated,
+ AsyncAutomated,
+ AutomatedWithRawResponse,
+ AsyncAutomatedWithRawResponse,
+)
+
+__all__ = [
+ "Automated",
+ "AsyncAutomated",
+ "AutomatedWithRawResponse",
+ "AsyncAutomatedWithRawResponse",
+ "Manual",
+ "AsyncManual",
+ "ManualWithRawResponse",
+ "AsyncManualWithRawResponse",
+ "Jobs",
+ "AsyncJobs",
+ "JobsWithRawResponse",
+ "AsyncJobsWithRawResponse",
+]
diff --git a/src/finch/resources/jobs/automated.py b/src/finch/resources/jobs/automated.py
new file mode 100644
index 00000000..9f43c60a
--- /dev/null
+++ b/src/finch/resources/jobs/automated.py
@@ -0,0 +1,318 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from typing_extensions import Literal
+
+import httpx
+
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._utils import maybe_transform
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
+from ...pagination import SyncPage, AsyncPage
+from ...types.jobs import (
+ AutomatedAsyncJob,
+ AutomatedCreateResponse,
+ automated_list_params,
+ automated_create_params,
+)
+from ..._base_client import AsyncPaginator, make_request_options
+
+if TYPE_CHECKING:
+ from ..._client import Finch, AsyncFinch
+
+__all__ = ["Automated", "AsyncAutomated"]
+
+
+class Automated(SyncAPIResource):
+ with_raw_response: AutomatedWithRawResponse
+
+ def __init__(self, client: Finch) -> None:
+ super().__init__(client)
+ self.with_raw_response = AutomatedWithRawResponse(self)
+
+ def create(
+ self,
+ *,
+ type: Literal["data_sync_all"],
+ # 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> AutomatedCreateResponse:
+ """Enqueue an automated job.
+
+ Currently, only the `data_sync_all` job type is
+ supported, which will enqueue a job to re-sync all data for a connection.
+ `data_sync_all` has a concurrency limit of 1 job at a time per connection. This
+ means that if this endpoint is called while a job is already in progress for
+ this connection, Finch will return the `job_id` of the job that is currently in
+ progress. Finch allows a fixed window rate limit of 1 forced refresh per hour
+ per connection.
+
+ This endpoint is available for _Scale_ tier customers as an add-on. To request
+ access to this endpoint, please contact your Finch account manager.
+
+ Args:
+ type: The type of job to start. Currently the only supported type is `data_sync_all`
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/jobs/automated",
+ body=maybe_transform({"type": type}, automated_create_params.AutomatedCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AutomatedCreateResponse,
+ )
+
+ def retrieve(
+ self,
+ job_id: str,
+ *,
+ # 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> AutomatedAsyncJob:
+ """
+ Get an automated job by `job_id`.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get(
+ f"/jobs/automated/{job_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AutomatedAsyncJob,
+ )
+
+ def list(
+ self,
+ *,
+ limit: int | NotGiven = NOT_GIVEN,
+ offset: int | 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> SyncPage[AutomatedAsyncJob]:
+ """Get all automated jobs.
+
+ Automated jobs are completed by a machine. By default,
+ jobs are sorted in descending order by submission time. For scheduled jobs such
+ as data syncs, only the next scheduled job is shown.
+
+ Args:
+ limit: Number of items to return
+
+ offset: Index to start from (defaults to 0)
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/jobs/automated",
+ page=SyncPage[AutomatedAsyncJob],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ automated_list_params.AutomatedListParams,
+ ),
+ ),
+ model=AutomatedAsyncJob,
+ )
+
+
+class AsyncAutomated(AsyncAPIResource):
+ with_raw_response: AsyncAutomatedWithRawResponse
+
+ def __init__(self, client: AsyncFinch) -> None:
+ super().__init__(client)
+ self.with_raw_response = AsyncAutomatedWithRawResponse(self)
+
+ async def create(
+ self,
+ *,
+ type: Literal["data_sync_all"],
+ # 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> AutomatedCreateResponse:
+ """Enqueue an automated job.
+
+ Currently, only the `data_sync_all` job type is
+ supported, which will enqueue a job to re-sync all data for a connection.
+ `data_sync_all` has a concurrency limit of 1 job at a time per connection. This
+ means that if this endpoint is called while a job is already in progress for
+ this connection, Finch will return the `job_id` of the job that is currently in
+ progress. Finch allows a fixed window rate limit of 1 forced refresh per hour
+ per connection.
+
+ This endpoint is available for _Scale_ tier customers as an add-on. To request
+ access to this endpoint, please contact your Finch account manager.
+
+ Args:
+ type: The type of job to start. Currently the only supported type is `data_sync_all`
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/jobs/automated",
+ body=maybe_transform({"type": type}, automated_create_params.AutomatedCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AutomatedCreateResponse,
+ )
+
+ async def retrieve(
+ self,
+ job_id: str,
+ *,
+ # 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> AutomatedAsyncJob:
+ """
+ Get an automated job by `job_id`.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._get(
+ f"/jobs/automated/{job_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AutomatedAsyncJob,
+ )
+
+ def list(
+ self,
+ *,
+ limit: int | NotGiven = NOT_GIVEN,
+ offset: int | 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> AsyncPaginator[AutomatedAsyncJob, AsyncPage[AutomatedAsyncJob]]:
+ """Get all automated jobs.
+
+ Automated jobs are completed by a machine. By default,
+ jobs are sorted in descending order by submission time. For scheduled jobs such
+ as data syncs, only the next scheduled job is shown.
+
+ Args:
+ limit: Number of items to return
+
+ offset: Index to start from (defaults to 0)
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/jobs/automated",
+ page=AsyncPage[AutomatedAsyncJob],
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "limit": limit,
+ "offset": offset,
+ },
+ automated_list_params.AutomatedListParams,
+ ),
+ ),
+ model=AutomatedAsyncJob,
+ )
+
+
+class AutomatedWithRawResponse:
+ def __init__(self, automated: Automated) -> None:
+ self.create = to_raw_response_wrapper(
+ automated.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ automated.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ automated.list,
+ )
+
+
+class AsyncAutomatedWithRawResponse:
+ def __init__(self, automated: AsyncAutomated) -> None:
+ self.create = async_to_raw_response_wrapper(
+ automated.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ automated.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ automated.list,
+ )
diff --git a/src/finch/resources/jobs/jobs.py b/src/finch/resources/jobs/jobs.py
new file mode 100644
index 00000000..f522c9c5
--- /dev/null
+++ b/src/finch/resources/jobs/jobs.py
@@ -0,0 +1,60 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from .manual import (
+ Manual,
+ AsyncManual,
+ ManualWithRawResponse,
+ AsyncManualWithRawResponse,
+)
+from .automated import (
+ Automated,
+ AsyncAutomated,
+ AutomatedWithRawResponse,
+ AsyncAutomatedWithRawResponse,
+)
+from ..._resource import SyncAPIResource, AsyncAPIResource
+
+if TYPE_CHECKING:
+ from ..._client import Finch, AsyncFinch
+
+__all__ = ["Jobs", "AsyncJobs"]
+
+
+class Jobs(SyncAPIResource):
+ automated: Automated
+ manual: Manual
+ with_raw_response: JobsWithRawResponse
+
+ def __init__(self, client: Finch) -> None:
+ super().__init__(client)
+ self.automated = Automated(client)
+ self.manual = Manual(client)
+ self.with_raw_response = JobsWithRawResponse(self)
+
+
+class AsyncJobs(AsyncAPIResource):
+ automated: AsyncAutomated
+ manual: AsyncManual
+ with_raw_response: AsyncJobsWithRawResponse
+
+ def __init__(self, client: AsyncFinch) -> None:
+ super().__init__(client)
+ self.automated = AsyncAutomated(client)
+ self.manual = AsyncManual(client)
+ self.with_raw_response = AsyncJobsWithRawResponse(self)
+
+
+class JobsWithRawResponse:
+ def __init__(self, jobs: Jobs) -> None:
+ self.automated = AutomatedWithRawResponse(jobs.automated)
+ self.manual = ManualWithRawResponse(jobs.manual)
+
+
+class AsyncJobsWithRawResponse:
+ def __init__(self, jobs: AsyncJobs) -> None:
+ self.automated = AsyncAutomatedWithRawResponse(jobs.automated)
+ self.manual = AsyncManualWithRawResponse(jobs.manual)
diff --git a/src/finch/resources/jobs/manual.py b/src/finch/resources/jobs/manual.py
new file mode 100644
index 00000000..9334f2da
--- /dev/null
+++ b/src/finch/resources/jobs/manual.py
@@ -0,0 +1,114 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import httpx
+
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
+from ...types.jobs import ManualAsyncJob
+from ..._base_client import make_request_options
+
+if TYPE_CHECKING:
+ from ..._client import Finch, AsyncFinch
+
+__all__ = ["Manual", "AsyncManual"]
+
+
+class Manual(SyncAPIResource):
+ with_raw_response: ManualWithRawResponse
+
+ def __init__(self, client: Finch) -> None:
+ super().__init__(client)
+ self.with_raw_response = ManualWithRawResponse(self)
+
+ def retrieve(
+ self,
+ job_id: str,
+ *,
+ # 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> ManualAsyncJob:
+ """Get a manual job by `job_id`.
+
+ Manual jobs are completed by a human and include
+ Assisted Benefits jobs.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get(
+ f"/jobs/manual/{job_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ManualAsyncJob,
+ )
+
+
+class AsyncManual(AsyncAPIResource):
+ with_raw_response: AsyncManualWithRawResponse
+
+ def __init__(self, client: AsyncFinch) -> None:
+ super().__init__(client)
+ self.with_raw_response = AsyncManualWithRawResponse(self)
+
+ async def retrieve(
+ self,
+ job_id: str,
+ *,
+ # 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> ManualAsyncJob:
+ """Get a manual job by `job_id`.
+
+ Manual jobs are completed by a human and include
+ Assisted Benefits jobs.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._get(
+ f"/jobs/manual/{job_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ManualAsyncJob,
+ )
+
+
+class ManualWithRawResponse:
+ def __init__(self, manual: Manual) -> None:
+ self.retrieve = to_raw_response_wrapper(
+ manual.retrieve,
+ )
+
+
+class AsyncManualWithRawResponse:
+ def __init__(self, manual: AsyncManual) -> None:
+ self.retrieve = async_to_raw_response_wrapper(
+ manual.retrieve,
+ )
diff --git a/src/finch/types/__init__.py b/src/finch/types/__init__.py
index eee945a5..f6a15f80 100644
--- a/src/finch/types/__init__.py
+++ b/src/finch/types/__init__.py
@@ -4,7 +4,7 @@
from .money import Money as Money
from .income import Income as Income
-from .paging import Paging as Paging
+from .shared import Paging as Paging
from .shared import OperationSupport as OperationSupport
from .shared import OperationSupportMatrix as OperationSupportMatrix
from .location import Location as Location
diff --git a/src/finch/types/hris/pay_statement_response_body.py b/src/finch/types/hris/pay_statement_response_body.py
index 712e442d..c7563aac 100644
--- a/src/finch/types/hris/pay_statement_response_body.py
+++ b/src/finch/types/hris/pay_statement_response_body.py
@@ -2,7 +2,7 @@
from typing import List, Optional
-from ..paging import Paging
+from ..shared import Paging
from ..._models import BaseModel
from .pay_statement import PayStatement
diff --git a/src/finch/types/jobs/__init__.py b/src/finch/types/jobs/__init__.py
new file mode 100644
index 00000000..25ad24cf
--- /dev/null
+++ b/src/finch/types/jobs/__init__.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+from .manual_async_job import ManualAsyncJob as ManualAsyncJob
+from .automated_async_job import AutomatedAsyncJob as AutomatedAsyncJob
+from .automated_list_params import AutomatedListParams as AutomatedListParams
+from .automated_create_params import AutomatedCreateParams as AutomatedCreateParams
+from .automated_create_response import (
+ AutomatedCreateResponse as AutomatedCreateResponse,
+)
diff --git a/src/finch/types/jobs/automated_async_job.py b/src/finch/types/jobs/automated_async_job.py
new file mode 100644
index 00000000..0b3e727d
--- /dev/null
+++ b/src/finch/types/jobs/automated_async_job.py
@@ -0,0 +1,42 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["AutomatedAsyncJob"]
+
+
+class AutomatedAsyncJob(BaseModel):
+ completed_at: Optional[datetime]
+ """The datetime the job completed."""
+
+ created_at: datetime
+ """The datetime when the job was created.
+
+ for scheduled jobs, this will be the initial connection time. For ad-hoc jobs,
+ this will be the time the creation request was received.
+ """
+
+ job_id: str
+ """The id of the job that has been created."""
+
+ job_url: str
+ """The url that can be used to retrieve the job status"""
+
+ scheduled_at: Optional[datetime]
+ """The datetime a job is scheduled to be run.
+
+ For scheduled jobs, this datetime can be in the future if the job has not yet
+ been enqueued. For ad-hoc jobs, this field will be null.
+ """
+
+ started_at: Optional[datetime]
+ """The datetime a job entered into the job queue."""
+
+ status: Literal["pending", "in_progress", "complete", "error", "reauth_error", "permissions_error"]
+
+ type: Literal["data_sync_all"]
+ """Only `data_sync_all` currently supported"""
diff --git a/src/finch/types/jobs/automated_create_params.py b/src/finch/types/jobs/automated_create_params.py
new file mode 100644
index 00000000..ea39170f
--- /dev/null
+++ b/src/finch/types/jobs/automated_create_params.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["AutomatedCreateParams"]
+
+
+class AutomatedCreateParams(TypedDict, total=False):
+ type: Required[Literal["data_sync_all"]]
+ """The type of job to start. Currently the only supported type is `data_sync_all`"""
diff --git a/src/finch/types/jobs/automated_create_response.py b/src/finch/types/jobs/automated_create_response.py
new file mode 100644
index 00000000..1341d52b
--- /dev/null
+++ b/src/finch/types/jobs/automated_create_response.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from ..._models import BaseModel
+
+__all__ = ["AutomatedCreateResponse"]
+
+
+class AutomatedCreateResponse(BaseModel):
+ allowed_refreshes: int
+ """The number of allowed refreshes per hour (per hour, fixed window)"""
+
+ job_id: str
+ """The id of the job that has been created."""
+
+ job_url: str
+ """The url that can be used to retrieve the job status"""
+
+ remaining_refreshes: int
+ """The number of remaining refreshes available (per hour, fixed window)"""
diff --git a/src/finch/types/jobs/automated_list_params.py b/src/finch/types/jobs/automated_list_params.py
new file mode 100644
index 00000000..4c24874f
--- /dev/null
+++ b/src/finch/types/jobs/automated_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["AutomatedListParams"]
+
+
+class AutomatedListParams(TypedDict, total=False):
+ limit: int
+ """Number of items to return"""
+
+ offset: int
+ """Index to start from (defaults to 0)"""
diff --git a/src/finch/types/jobs/manual_async_job.py b/src/finch/types/jobs/manual_async_job.py
new file mode 100644
index 00000000..0f831fb0
--- /dev/null
+++ b/src/finch/types/jobs/manual_async_job.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["ManualAsyncJob"]
+
+
+class ManualAsyncJob(BaseModel):
+ body: Optional[List[object]]
+ """Specific information about the job, such as individual statuses for batch jobs."""
+
+ job_id: str
+
+ status: Literal["pending", "in_progress", "error", "complete"]
diff --git a/src/finch/types/shared/__init__.py b/src/finch/types/shared/__init__.py
index 3be971aa..6c699bd7 100644
--- a/src/finch/types/shared/__init__.py
+++ b/src/finch/types/shared/__init__.py
@@ -1,4 +1,5 @@
# File generated from our OpenAPI spec by Stainless.
+from .paging import Paging as Paging
from .operation_support import OperationSupport as OperationSupport
from .operation_support_matrix import OperationSupportMatrix as OperationSupportMatrix
diff --git a/src/finch/types/paging.py b/src/finch/types/shared/paging.py
similarity index 91%
rename from src/finch/types/paging.py
rename to src/finch/types/shared/paging.py
index 296a46f6..726478fa 100644
--- a/src/finch/types/paging.py
+++ b/src/finch/types/shared/paging.py
@@ -2,7 +2,7 @@
from typing import Optional
-from .._models import BaseModel
+from ..._models import BaseModel
__all__ = ["Paging"]
diff --git a/src/finch/types/shared_params/__init__.py b/src/finch/types/shared_params/__init__.py
index 3be971aa..6c699bd7 100644
--- a/src/finch/types/shared_params/__init__.py
+++ b/src/finch/types/shared_params/__init__.py
@@ -1,4 +1,5 @@
# File generated from our OpenAPI spec by Stainless.
+from .paging import Paging as Paging
from .operation_support import OperationSupport as OperationSupport
from .operation_support_matrix import OperationSupportMatrix as OperationSupportMatrix
diff --git a/src/finch/types/shared_params/paging.py b/src/finch/types/shared_params/paging.py
new file mode 100644
index 00000000..e3ea2ca9
--- /dev/null
+++ b/src/finch/types/shared_params/paging.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["Paging"]
+
+
+class Paging(TypedDict, total=False):
+ count: int
+ """The total number of elements for the entire query (not just the given page)"""
+
+ offset: int
+ """The current start index of the returned list of elements"""
diff --git a/tests/api_resources/jobs/__init__.py b/tests/api_resources/jobs/__init__.py
new file mode 100644
index 00000000..1016754e
--- /dev/null
+++ b/tests/api_resources/jobs/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless.
diff --git a/tests/api_resources/jobs/test_automated.py b/tests/api_resources/jobs/test_automated.py
new file mode 100644
index 00000000..ae4ff4fa
--- /dev/null
+++ b/tests/api_resources/jobs/test_automated.py
@@ -0,0 +1,132 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+import os
+
+import pytest
+
+from finch import Finch, AsyncFinch
+from tests.utils import assert_matches_type
+from finch._client import Finch, AsyncFinch
+from finch.pagination import SyncPage, AsyncPage
+from finch.types.jobs import AutomatedAsyncJob, AutomatedCreateResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+access_token = "My Access Token"
+
+
+class TestAutomated:
+ strict_client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
+ loose_client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=False)
+ parametrize = pytest.mark.parametrize("client", [strict_client, loose_client], ids=["strict", "loose"])
+
+ @parametrize
+ def test_method_create(self, client: Finch) -> None:
+ automated = client.jobs.automated.create(
+ type="data_sync_all",
+ )
+ assert_matches_type(AutomatedCreateResponse, automated, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Finch) -> None:
+ response = client.jobs.automated.with_raw_response.create(
+ type="data_sync_all",
+ )
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ automated = response.parse()
+ assert_matches_type(AutomatedCreateResponse, automated, path=["response"])
+
+ @parametrize
+ def test_method_retrieve(self, client: Finch) -> None:
+ automated = client.jobs.automated.retrieve(
+ "string",
+ )
+ assert_matches_type(AutomatedAsyncJob, automated, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Finch) -> None:
+ response = client.jobs.automated.with_raw_response.retrieve(
+ "string",
+ )
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ automated = response.parse()
+ assert_matches_type(AutomatedAsyncJob, automated, path=["response"])
+
+ @parametrize
+ def test_method_list(self, client: Finch) -> None:
+ automated = client.jobs.automated.list()
+ assert_matches_type(SyncPage[AutomatedAsyncJob], automated, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Finch) -> None:
+ automated = client.jobs.automated.list(
+ limit=0,
+ offset=0,
+ )
+ assert_matches_type(SyncPage[AutomatedAsyncJob], automated, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Finch) -> None:
+ response = client.jobs.automated.with_raw_response.list()
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ automated = response.parse()
+ assert_matches_type(SyncPage[AutomatedAsyncJob], automated, path=["response"])
+
+
+class TestAsyncAutomated:
+ strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
+ loose_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=False)
+ parametrize = pytest.mark.parametrize("client", [strict_client, loose_client], ids=["strict", "loose"])
+
+ @parametrize
+ async def test_method_create(self, client: AsyncFinch) -> None:
+ automated = await client.jobs.automated.create(
+ type="data_sync_all",
+ )
+ assert_matches_type(AutomatedCreateResponse, automated, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, client: AsyncFinch) -> None:
+ response = await client.jobs.automated.with_raw_response.create(
+ type="data_sync_all",
+ )
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ automated = response.parse()
+ assert_matches_type(AutomatedCreateResponse, automated, path=["response"])
+
+ @parametrize
+ async def test_method_retrieve(self, client: AsyncFinch) -> None:
+ automated = await client.jobs.automated.retrieve(
+ "string",
+ )
+ assert_matches_type(AutomatedAsyncJob, automated, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, client: AsyncFinch) -> None:
+ response = await client.jobs.automated.with_raw_response.retrieve(
+ "string",
+ )
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ automated = response.parse()
+ assert_matches_type(AutomatedAsyncJob, automated, path=["response"])
+
+ @parametrize
+ async def test_method_list(self, client: AsyncFinch) -> None:
+ automated = await client.jobs.automated.list()
+ assert_matches_type(AsyncPage[AutomatedAsyncJob], automated, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, client: AsyncFinch) -> None:
+ automated = await client.jobs.automated.list(
+ limit=0,
+ offset=0,
+ )
+ assert_matches_type(AsyncPage[AutomatedAsyncJob], automated, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, client: AsyncFinch) -> None:
+ response = await client.jobs.automated.with_raw_response.list()
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ automated = response.parse()
+ assert_matches_type(AsyncPage[AutomatedAsyncJob], automated, path=["response"])
diff --git a/tests/api_resources/jobs/test_manual.py b/tests/api_resources/jobs/test_manual.py
new file mode 100644
index 00000000..9df08a02
--- /dev/null
+++ b/tests/api_resources/jobs/test_manual.py
@@ -0,0 +1,59 @@
+# File generated from our OpenAPI spec by Stainless.
+
+from __future__ import annotations
+
+import os
+
+import pytest
+
+from finch import Finch, AsyncFinch
+from tests.utils import assert_matches_type
+from finch._client import Finch, AsyncFinch
+from finch.types.jobs import ManualAsyncJob
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+access_token = "My Access Token"
+
+
+class TestManual:
+ strict_client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
+ loose_client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=False)
+ parametrize = pytest.mark.parametrize("client", [strict_client, loose_client], ids=["strict", "loose"])
+
+ @parametrize
+ def test_method_retrieve(self, client: Finch) -> None:
+ manual = client.jobs.manual.retrieve(
+ "string",
+ )
+ assert_matches_type(ManualAsyncJob, manual, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Finch) -> None:
+ response = client.jobs.manual.with_raw_response.retrieve(
+ "string",
+ )
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ manual = response.parse()
+ assert_matches_type(ManualAsyncJob, manual, path=["response"])
+
+
+class TestAsyncManual:
+ strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
+ loose_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=False)
+ parametrize = pytest.mark.parametrize("client", [strict_client, loose_client], ids=["strict", "loose"])
+
+ @parametrize
+ async def test_method_retrieve(self, client: AsyncFinch) -> None:
+ manual = await client.jobs.manual.retrieve(
+ "string",
+ )
+ assert_matches_type(ManualAsyncJob, manual, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, client: AsyncFinch) -> None:
+ response = await client.jobs.manual.with_raw_response.retrieve(
+ "string",
+ )
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ manual = response.parse()
+ assert_matches_type(ManualAsyncJob, manual, path=["response"])
From d354f0a501deeea8090c0e2a6200302fe40a7638 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Tue, 5 Dec 2023 16:03:19 +0000
Subject: [PATCH 11/26] feat(api): add `client_type` and `connection_type` to
introspection (#211)
---
src/finch/types/introspection.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/finch/types/introspection.py b/src/finch/types/introspection.py
index b9d15202..c4e6178d 100644
--- a/src/finch/types/introspection.py
+++ b/src/finch/types/introspection.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless.
from typing import List
+from typing_extensions import Literal
from .._models import BaseModel
@@ -14,9 +15,18 @@ class Introspection(BaseModel):
client_id: str
"""The client id of the application associated with the `access_token`."""
+ client_type: Literal["production", "development", "sandbox"]
+ """The type of application associated with a token."""
+
company_id: str
"""The Finch uuid of the company associated with the `access_token`."""
+ connection_type: Literal["provider", "finch"]
+ """
+ The type of the connection associated with the token.
`provider` -
+ connection to an external provider
`finch` - finch-generated data.
+ """
+
manual: bool
"""
Whether the connection associated with the `access_token` uses the Assisted
From ff189d86c46bf3ac0e6900d849eea5568c6d1d40 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Wed, 6 Dec 2023 01:03:55 +0000
Subject: [PATCH 12/26] ci: remove PR title linter (#212)
---
.github/workflows/lint-pr.yml | 21 ---------------------
1 file changed, 21 deletions(-)
delete mode 100644 .github/workflows/lint-pr.yml
diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml
deleted file mode 100644
index 82ee9e18..00000000
--- a/.github/workflows/lint-pr.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-name: "Lint PR"
-
-on:
- pull_request_target:
- types:
- - opened
- - edited
- - synchronize
-
-permissions:
- pull-requests: read
-
-jobs:
- pr_title:
- name: Validate PR title
- runs-on: ubuntu-latest
- if: github.ref == 'refs/heads/main' && github.repository == 'Finch-API/finch-api-python'
- steps:
- - uses: amannn/action-semantic-pull-request@v5
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
From 81a6e2f22a5c5fe862c693a0b5b2affda78d88af Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Thu, 7 Dec 2023 10:09:16 +0000
Subject: [PATCH 13/26] chore(internal): reformat imports (#213)
---
pyproject.toml | 37 ++++-----
requirements-dev.lock | 3 +-
src/finch/_client.py | 3 +-
src/finch/_compat.py | 30 ++++----
src/finch/_models.py | 14 +---
src/finch/_types.py | 9 +--
src/finch/_utils/__init__.py | 76 ++++++++++---------
src/finch/_utils/_utils.py | 4 +-
src/finch/resources/__init__.py | 14 +---
src/finch/resources/account.py | 12 ++-
src/finch/resources/hris/__init__.py | 35 ++-------
src/finch/resources/hris/benefits/__init__.py | 14 +---
src/finch/resources/hris/benefits/benefits.py | 20 +++--
.../resources/hris/benefits/individuals.py | 13 +++-
src/finch/resources/hris/company.py | 12 ++-
src/finch/resources/hris/directory.py | 18 ++++-
src/finch/resources/hris/employments.py | 13 +++-
src/finch/resources/hris/hris.py | 35 ++-------
src/finch/resources/hris/individuals.py | 13 +++-
src/finch/resources/hris/pay_statements.py | 13 +++-
src/finch/resources/hris/payments.py | 13 +++-
src/finch/resources/jobs/__init__.py | 14 +---
src/finch/resources/jobs/automated.py | 13 +++-
src/finch/resources/jobs/jobs.py | 14 +---
src/finch/resources/jobs/manual.py | 12 ++-
src/finch/resources/providers.py | 13 +++-
src/finch/resources/request_forwarding.py | 17 ++++-
src/finch/resources/webhooks.py | 8 +-
src/finch/types/__init__.py | 8 +-
src/finch/types/hris/__init__.py | 32 ++------
src/finch/types/hris/benefits/__init__.py | 12 +--
src/finch/types/hris/benfit_contribution.py | 2 +
src/finch/types/jobs/__init__.py | 4 +-
tests/utils.py | 7 +-
34 files changed, 280 insertions(+), 277 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index b831f420..59fcb8e2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -46,16 +46,16 @@ Repository = "https://github.com/Finch-API/finch-api-python"
[tool.rye]
managed = true
dev-dependencies = [
- "pyright==1.1.332",
- "mypy==1.7.1",
- "black==23.3.0",
- "respx==0.20.2",
- "pytest==7.1.1",
- "pytest-asyncio==0.21.1",
- "ruff==0.0.282",
- "isort==5.10.1",
- "time-machine==2.9.0",
- "nox==2023.4.22",
+ # version pins are in requirements-dev.lock
+ "pyright",
+ "mypy",
+ "black",
+ "respx",
+ "pytest",
+ "pytest-asyncio",
+ "ruff",
+ "time-machine",
+ "nox",
"dirty-equals>=0.6.0",
]
@@ -65,12 +65,10 @@ format = { chain = [
"format:black",
"format:docs",
"format:ruff",
- "format:isort",
]}
"format:black" = "black ."
"format:docs" = "python bin/blacken-docs.py README.md api.md"
"format:ruff" = "ruff --fix ."
-"format:isort" = "isort ."
"check:ruff" = "ruff ."
@@ -125,16 +123,13 @@ reportImplicitOverride = true
reportImportCycles = false
reportPrivateUsage = false
-[tool.isort]
-profile = "black"
-length_sort = true
-extra_standard_library = ["typing_extensions"]
-
[tool.ruff]
line-length = 120
-format = "grouped"
+output-format = "grouped"
target-version = "py37"
select = [
+ # isort
+ "I",
# remove unused imports
"F401",
# bare except statements
@@ -152,6 +147,12 @@ unfixable = [
]
ignore-init-module-imports = true
+[tool.ruff.lint.isort]
+length-sort = true
+length-sort-straight = true
+combine-as-imports = true
+extra-standard-library = ["typing_extensions"]
+known-first-party = ["finch", "tests"]
[tool.ruff.per-file-ignores]
"bin/**.py" = ["T201", "T203"]
diff --git a/requirements-dev.lock b/requirements-dev.lock
index ce154682..36843262 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -25,7 +25,6 @@ httpcore==1.0.2
httpx==0.25.2
idna==3.4
iniconfig==2.0.0
-isort==5.10.1
mypy==1.7.1
mypy-extensions==1.0.0
nodeenv==1.8.0
@@ -43,7 +42,7 @@ pytest-asyncio==0.21.1
python-dateutil==2.8.2
pytz==2023.3.post1
respx==0.20.2
-ruff==0.0.282
+ruff==0.1.7
six==1.16.0
sniffio==1.3.0
time-machine==2.9.0
diff --git a/src/finch/_client.py b/src/finch/_client.py
index 149406a0..01252f1f 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -24,8 +24,7 @@
)
from ._utils import is_given, get_async_library
from ._version import __version__
-from ._streaming import Stream as Stream
-from ._streaming import AsyncStream as AsyncStream
+from ._streaming import Stream as Stream, AsyncStream as AsyncStream
from ._exceptions import APIStatusError
from ._base_client import (
DEFAULT_LIMITS,
diff --git a/src/finch/_compat.py b/src/finch/_compat.py
index 34323c9b..d95db8ed 100644
--- a/src/finch/_compat.py
+++ b/src/finch/_compat.py
@@ -43,21 +43,23 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001
else:
if PYDANTIC_V2:
- from pydantic.v1.typing import get_args as get_args
- from pydantic.v1.typing import is_union as is_union
- from pydantic.v1.typing import get_origin as get_origin
- from pydantic.v1.typing import is_typeddict as is_typeddict
- from pydantic.v1.typing import is_literal_type as is_literal_type
- from pydantic.v1.datetime_parse import parse_date as parse_date
- from pydantic.v1.datetime_parse import parse_datetime as parse_datetime
+ from pydantic.v1.typing import (
+ get_args as get_args,
+ is_union as is_union,
+ get_origin as get_origin,
+ is_typeddict as is_typeddict,
+ is_literal_type as is_literal_type,
+ )
+ from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
else:
- from pydantic.typing import get_args as get_args
- from pydantic.typing import is_union as is_union
- from pydantic.typing import get_origin as get_origin
- from pydantic.typing import is_typeddict as is_typeddict
- from pydantic.typing import is_literal_type as is_literal_type
- from pydantic.datetime_parse import parse_date as parse_date
- from pydantic.datetime_parse import parse_datetime as parse_datetime
+ from pydantic.typing import (
+ get_args as get_args,
+ is_union as is_union,
+ get_origin as get_origin,
+ is_typeddict as is_typeddict,
+ is_literal_type as is_literal_type,
+ )
+ from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
# refactored config
diff --git a/src/finch/_models.py b/src/finch/_models.py
index 5b8c9601..cdd44ccb 100644
--- a/src/finch/_models.py
+++ b/src/finch/_models.py
@@ -30,17 +30,11 @@
AnyMapping,
HttpxRequestFiles,
)
-from ._utils import (
- is_list,
- is_given,
- is_mapping,
- parse_date,
- parse_datetime,
- strip_not_given,
-)
-from ._compat import PYDANTIC_V2, ConfigDict
-from ._compat import GenericModel as BaseGenericModel
+from ._utils import is_list, is_given, is_mapping, parse_date, parse_datetime, strip_not_given
from ._compat import (
+ PYDANTIC_V2,
+ ConfigDict,
+ GenericModel as BaseGenericModel,
get_args,
is_union,
parse_obj,
diff --git a/src/finch/_types.py b/src/finch/_types.py
index e12f064d..7f82cf4a 100644
--- a/src/finch/_types.py
+++ b/src/finch/_types.py
@@ -19,14 +19,7 @@
Sequence,
AsyncIterator,
)
-from typing_extensions import (
- Literal,
- Protocol,
- TypeAlias,
- TypedDict,
- override,
- runtime_checkable,
-)
+from typing_extensions import Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable
import pydantic
from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport
diff --git a/src/finch/_utils/__init__.py b/src/finch/_utils/__init__.py
index 400ca9b8..e98636c9 100644
--- a/src/finch/_utils/__init__.py
+++ b/src/finch/_utils/__init__.py
@@ -1,37 +1,41 @@
from ._proxy import LazyProxy as LazyProxy
-from ._utils import flatten as flatten
-from ._utils import is_dict as is_dict
-from ._utils import is_list as is_list
-from ._utils import is_given as is_given
-from ._utils import is_tuple as is_tuple
-from ._utils import is_mapping as is_mapping
-from ._utils import is_tuple_t as is_tuple_t
-from ._utils import parse_date as parse_date
-from ._utils import is_sequence as is_sequence
-from ._utils import coerce_float as coerce_float
-from ._utils import is_list_type as is_list_type
-from ._utils import is_mapping_t as is_mapping_t
-from ._utils import removeprefix as removeprefix
-from ._utils import removesuffix as removesuffix
-from ._utils import extract_files as extract_files
-from ._utils import is_sequence_t as is_sequence_t
-from ._utils import is_union_type as is_union_type
-from ._utils import required_args as required_args
-from ._utils import coerce_boolean as coerce_boolean
-from ._utils import coerce_integer as coerce_integer
-from ._utils import file_from_path as file_from_path
-from ._utils import parse_datetime as parse_datetime
-from ._utils import strip_not_given as strip_not_given
-from ._utils import deepcopy_minimal as deepcopy_minimal
-from ._utils import extract_type_arg as extract_type_arg
-from ._utils import is_required_type as is_required_type
-from ._utils import get_async_library as get_async_library
-from ._utils import is_annotated_type as is_annotated_type
-from ._utils import maybe_coerce_float as maybe_coerce_float
-from ._utils import get_required_header as get_required_header
-from ._utils import maybe_coerce_boolean as maybe_coerce_boolean
-from ._utils import maybe_coerce_integer as maybe_coerce_integer
-from ._utils import strip_annotated_type as strip_annotated_type
-from ._transform import PropertyInfo as PropertyInfo
-from ._transform import transform as transform
-from ._transform import maybe_transform as maybe_transform
+from ._utils import (
+ flatten as flatten,
+ is_dict as is_dict,
+ is_list as is_list,
+ is_given as is_given,
+ is_tuple as is_tuple,
+ is_mapping as is_mapping,
+ is_tuple_t as is_tuple_t,
+ parse_date as parse_date,
+ is_sequence as is_sequence,
+ coerce_float as coerce_float,
+ is_list_type as is_list_type,
+ is_mapping_t as is_mapping_t,
+ removeprefix as removeprefix,
+ removesuffix as removesuffix,
+ extract_files as extract_files,
+ is_sequence_t as is_sequence_t,
+ is_union_type as is_union_type,
+ required_args as required_args,
+ coerce_boolean as coerce_boolean,
+ coerce_integer as coerce_integer,
+ file_from_path as file_from_path,
+ parse_datetime as parse_datetime,
+ strip_not_given as strip_not_given,
+ deepcopy_minimal as deepcopy_minimal,
+ extract_type_arg as extract_type_arg,
+ is_required_type as is_required_type,
+ get_async_library as get_async_library,
+ is_annotated_type as is_annotated_type,
+ maybe_coerce_float as maybe_coerce_float,
+ get_required_header as get_required_header,
+ maybe_coerce_boolean as maybe_coerce_boolean,
+ maybe_coerce_integer as maybe_coerce_integer,
+ strip_annotated_type as strip_annotated_type,
+)
+from ._transform import (
+ PropertyInfo as PropertyInfo,
+ transform as transform,
+ maybe_transform as maybe_transform,
+)
diff --git a/src/finch/_utils/_utils.py b/src/finch/_utils/_utils.py
index 83f88cc3..cce69238 100644
--- a/src/finch/_utils/_utils.py
+++ b/src/finch/_utils/_utils.py
@@ -21,9 +21,7 @@
import sniffio
from .._types import Headers, NotGiven, FileTypes, NotGivenOr, HeadersLike
-from .._compat import is_union as _is_union
-from .._compat import parse_date as parse_date
-from .._compat import parse_datetime as parse_datetime
+from .._compat import is_union as _is_union, parse_date as parse_date, parse_datetime as parse_datetime
_T = TypeVar("_T")
_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...])
diff --git a/src/finch/resources/__init__.py b/src/finch/resources/__init__.py
index dcab5333..32d0cf28 100644
--- a/src/finch/resources/__init__.py
+++ b/src/finch/resources/__init__.py
@@ -2,19 +2,9 @@
from .hris import HRIS, AsyncHRIS, HRISWithRawResponse, AsyncHRISWithRawResponse
from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse
-from .account import (
- Account,
- AsyncAccount,
- AccountWithRawResponse,
- AsyncAccountWithRawResponse,
-)
+from .account import Account, AsyncAccount, AccountWithRawResponse, AsyncAccountWithRawResponse
from .webhooks import Webhooks, AsyncWebhooks
-from .providers import (
- Providers,
- AsyncProviders,
- ProvidersWithRawResponse,
- AsyncProvidersWithRawResponse,
-)
+from .providers import Providers, AsyncProviders, ProvidersWithRawResponse, AsyncProvidersWithRawResponse
from .request_forwarding import (
RequestForwarding,
AsyncRequestForwarding,
diff --git a/src/finch/resources/account.py b/src/finch/resources/account.py
index 5d90dfdc..0cb7b3aa 100644
--- a/src/finch/resources/account.py
+++ b/src/finch/resources/account.py
@@ -7,10 +7,18 @@
import httpx
from ..types import Introspection, DisconnectResponse
-from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from .._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper
-from .._base_client import make_request_options
+from .._base_client import (
+ make_request_options,
+)
if TYPE_CHECKING:
from .._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/__init__.py b/src/finch/resources/hris/__init__.py
index 4659abb9..8f292e8f 100644
--- a/src/finch/resources/hris/__init__.py
+++ b/src/finch/resources/hris/__init__.py
@@ -7,36 +7,11 @@
CompanyResourceWithRawResponse,
AsyncCompanyResourceWithRawResponse,
)
-from .benefits import (
- Benefits,
- AsyncBenefits,
- BenefitsWithRawResponse,
- AsyncBenefitsWithRawResponse,
-)
-from .payments import (
- Payments,
- AsyncPayments,
- PaymentsWithRawResponse,
- AsyncPaymentsWithRawResponse,
-)
-from .directory import (
- Directory,
- AsyncDirectory,
- DirectoryWithRawResponse,
- AsyncDirectoryWithRawResponse,
-)
-from .employments import (
- Employments,
- AsyncEmployments,
- EmploymentsWithRawResponse,
- AsyncEmploymentsWithRawResponse,
-)
-from .individuals import (
- Individuals,
- AsyncIndividuals,
- IndividualsWithRawResponse,
- AsyncIndividualsWithRawResponse,
-)
+from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse
+from .payments import Payments, AsyncPayments, PaymentsWithRawResponse, AsyncPaymentsWithRawResponse
+from .directory import Directory, AsyncDirectory, DirectoryWithRawResponse, AsyncDirectoryWithRawResponse
+from .employments import Employments, AsyncEmployments, EmploymentsWithRawResponse, AsyncEmploymentsWithRawResponse
+from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse
from .pay_statements import (
PayStatements,
AsyncPayStatements,
diff --git a/src/finch/resources/hris/benefits/__init__.py b/src/finch/resources/hris/benefits/__init__.py
index fbbe99ea..9a5b9063 100644
--- a/src/finch/resources/hris/benefits/__init__.py
+++ b/src/finch/resources/hris/benefits/__init__.py
@@ -1,17 +1,7 @@
# File generated from our OpenAPI spec by Stainless.
-from .benefits import (
- Benefits,
- AsyncBenefits,
- BenefitsWithRawResponse,
- AsyncBenefitsWithRawResponse,
-)
-from .individuals import (
- Individuals,
- AsyncIndividuals,
- IndividualsWithRawResponse,
- AsyncIndividualsWithRawResponse,
-)
+from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse
+from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse
__all__ = [
"Individuals",
diff --git a/src/finch/resources/hris/benefits/benefits.py b/src/finch/resources/hris/benefits/benefits.py
index f90a5100..4752a838 100644
--- a/src/finch/resources/hris/benefits/benefits.py
+++ b/src/finch/resources/hris/benefits/benefits.py
@@ -6,14 +6,15 @@
import httpx
-from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
-from ...._utils import maybe_transform
-from .individuals import (
- Individuals,
- AsyncIndividuals,
- IndividualsWithRawResponse,
- AsyncIndividualsWithRawResponse,
+from ...._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
)
+from ...._utils import maybe_transform
+from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse
from ...._resource import SyncAPIResource, AsyncAPIResource
from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ....pagination import SyncSinglePage, AsyncSinglePage
@@ -27,7 +28,10 @@
benefit_create_params,
benefit_update_params,
)
-from ...._base_client import AsyncPaginator, make_request_options
+from ...._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
if TYPE_CHECKING:
from ...._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/benefits/individuals.py b/src/finch/resources/hris/benefits/individuals.py
index fb4b3450..cb09ddf4 100644
--- a/src/finch/resources/hris/benefits/individuals.py
+++ b/src/finch/resources/hris/benefits/individuals.py
@@ -6,12 +6,21 @@
import httpx
-from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ...._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ...._utils import maybe_transform
from ...._resource import SyncAPIResource, AsyncAPIResource
from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ....pagination import SyncSinglePage, AsyncSinglePage
-from ...._base_client import AsyncPaginator, make_request_options
+from ...._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
from ....types.hris.benefits import (
IndividualBenefit,
EnrolledIndividual,
diff --git a/src/finch/resources/hris/company.py b/src/finch/resources/hris/company.py
index af6d6441..3ee67da7 100644
--- a/src/finch/resources/hris/company.py
+++ b/src/finch/resources/hris/company.py
@@ -6,11 +6,19 @@
import httpx
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...types.hris import Company
-from ..._base_client import make_request_options
+from ..._base_client import (
+ make_request_options,
+)
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/directory.py b/src/finch/resources/hris/directory.py
index ff3950aa..221586f6 100644
--- a/src/finch/resources/hris/directory.py
+++ b/src/finch/resources/hris/directory.py
@@ -7,13 +7,25 @@
import httpx
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncIndividualsPage, AsyncIndividualsPage
-from ...types.hris import IndividualInDirectory, directory_list_params
-from ..._base_client import AsyncPaginator, make_request_options
+from ...types.hris import (
+ IndividualInDirectory,
+ directory_list_params,
+)
+from ..._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/employments.py b/src/finch/resources/hris/employments.py
index 0b16202e..c0bd79ba 100644
--- a/src/finch/resources/hris/employments.py
+++ b/src/finch/resources/hris/employments.py
@@ -6,13 +6,22 @@
import httpx
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncResponsesPage, AsyncResponsesPage
from ...types.hris import EmploymentDataResponse, employment_retrieve_many_params
-from ..._base_client import AsyncPaginator, make_request_options
+from ..._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/hris.py b/src/finch/resources/hris/hris.py
index 8cd4f554..0ba66160 100644
--- a/src/finch/resources/hris/hris.py
+++ b/src/finch/resources/hris/hris.py
@@ -10,37 +10,12 @@
CompanyResourceWithRawResponse,
AsyncCompanyResourceWithRawResponse,
)
-from .benefits import (
- Benefits,
- AsyncBenefits,
- BenefitsWithRawResponse,
- AsyncBenefitsWithRawResponse,
-)
-from .payments import (
- Payments,
- AsyncPayments,
- PaymentsWithRawResponse,
- AsyncPaymentsWithRawResponse,
-)
-from .directory import (
- Directory,
- AsyncDirectory,
- DirectoryWithRawResponse,
- AsyncDirectoryWithRawResponse,
-)
+from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse
+from .payments import Payments, AsyncPayments, PaymentsWithRawResponse, AsyncPaymentsWithRawResponse
+from .directory import Directory, AsyncDirectory, DirectoryWithRawResponse, AsyncDirectoryWithRawResponse
from ..._resource import SyncAPIResource, AsyncAPIResource
-from .employments import (
- Employments,
- AsyncEmployments,
- EmploymentsWithRawResponse,
- AsyncEmploymentsWithRawResponse,
-)
-from .individuals import (
- Individuals,
- AsyncIndividuals,
- IndividualsWithRawResponse,
- AsyncIndividualsWithRawResponse,
-)
+from .employments import Employments, AsyncEmployments, EmploymentsWithRawResponse, AsyncEmploymentsWithRawResponse
+from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse
from .pay_statements import (
PayStatements,
AsyncPayStatements,
diff --git a/src/finch/resources/hris/individuals.py b/src/finch/resources/hris/individuals.py
index 892eb820..8ca24125 100644
--- a/src/finch/resources/hris/individuals.py
+++ b/src/finch/resources/hris/individuals.py
@@ -6,13 +6,22 @@
import httpx
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncResponsesPage, AsyncResponsesPage
from ...types.hris import IndividualResponse, individual_retrieve_many_params
-from ..._base_client import AsyncPaginator, make_request_options
+from ..._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/pay_statements.py b/src/finch/resources/hris/pay_statements.py
index 4c444e9b..6ad4be76 100644
--- a/src/finch/resources/hris/pay_statements.py
+++ b/src/finch/resources/hris/pay_statements.py
@@ -6,13 +6,22 @@
import httpx
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncResponsesPage, AsyncResponsesPage
from ...types.hris import PayStatementResponse, pay_statement_retrieve_many_params
-from ..._base_client import AsyncPaginator, make_request_options
+from ..._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/payments.py b/src/finch/resources/hris/payments.py
index 17364d80..d5d0b28d 100644
--- a/src/finch/resources/hris/payments.py
+++ b/src/finch/resources/hris/payments.py
@@ -7,13 +7,22 @@
import httpx
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncSinglePage, AsyncSinglePage
from ...types.hris import Payment, payment_list_params
-from ..._base_client import AsyncPaginator, make_request_options
+from ..._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/jobs/__init__.py b/src/finch/resources/jobs/__init__.py
index f1f7692d..112d3130 100644
--- a/src/finch/resources/jobs/__init__.py
+++ b/src/finch/resources/jobs/__init__.py
@@ -1,18 +1,8 @@
# File generated from our OpenAPI spec by Stainless.
from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse
-from .manual import (
- Manual,
- AsyncManual,
- ManualWithRawResponse,
- AsyncManualWithRawResponse,
-)
-from .automated import (
- Automated,
- AsyncAutomated,
- AutomatedWithRawResponse,
- AsyncAutomatedWithRawResponse,
-)
+from .manual import Manual, AsyncManual, ManualWithRawResponse, AsyncManualWithRawResponse
+from .automated import Automated, AsyncAutomated, AutomatedWithRawResponse, AsyncAutomatedWithRawResponse
__all__ = [
"Automated",
diff --git a/src/finch/resources/jobs/automated.py b/src/finch/resources/jobs/automated.py
index 9f43c60a..48f2199b 100644
--- a/src/finch/resources/jobs/automated.py
+++ b/src/finch/resources/jobs/automated.py
@@ -7,7 +7,13 @@
import httpx
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
@@ -18,7 +24,10 @@
automated_list_params,
automated_create_params,
)
-from ..._base_client import AsyncPaginator, make_request_options
+from ..._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/jobs/jobs.py b/src/finch/resources/jobs/jobs.py
index f522c9c5..a47c4ddd 100644
--- a/src/finch/resources/jobs/jobs.py
+++ b/src/finch/resources/jobs/jobs.py
@@ -4,18 +4,8 @@
from typing import TYPE_CHECKING
-from .manual import (
- Manual,
- AsyncManual,
- ManualWithRawResponse,
- AsyncManualWithRawResponse,
-)
-from .automated import (
- Automated,
- AsyncAutomated,
- AutomatedWithRawResponse,
- AsyncAutomatedWithRawResponse,
-)
+from .manual import Manual, AsyncManual, ManualWithRawResponse, AsyncManualWithRawResponse
+from .automated import Automated, AsyncAutomated, AutomatedWithRawResponse, AsyncAutomatedWithRawResponse
from ..._resource import SyncAPIResource, AsyncAPIResource
if TYPE_CHECKING:
diff --git a/src/finch/resources/jobs/manual.py b/src/finch/resources/jobs/manual.py
index 9334f2da..61f16619 100644
--- a/src/finch/resources/jobs/manual.py
+++ b/src/finch/resources/jobs/manual.py
@@ -6,11 +6,19 @@
import httpx
-from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...types.jobs import ManualAsyncJob
-from ..._base_client import make_request_options
+from ..._base_client import (
+ make_request_options,
+)
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/providers.py b/src/finch/resources/providers.py
index aa6eedc5..5f8b17c7 100644
--- a/src/finch/resources/providers.py
+++ b/src/finch/resources/providers.py
@@ -7,11 +7,20 @@
import httpx
from ..types import Provider
-from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from .._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ..pagination import SyncSinglePage, AsyncSinglePage
-from .._base_client import AsyncPaginator, make_request_options
+from .._base_client import (
+ AsyncPaginator,
+ make_request_options,
+)
if TYPE_CHECKING:
from .._client import Finch, AsyncFinch
diff --git a/src/finch/resources/request_forwarding.py b/src/finch/resources/request_forwarding.py
index 2464bb35..4c571b39 100644
--- a/src/finch/resources/request_forwarding.py
+++ b/src/finch/resources/request_forwarding.py
@@ -6,12 +6,23 @@
import httpx
-from ..types import RequestForwardingForwardResponse, request_forwarding_forward_params
-from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..types import (
+ RequestForwardingForwardResponse,
+ request_forwarding_forward_params,
+)
+from .._types import (
+ NOT_GIVEN,
+ Body,
+ Query,
+ Headers,
+ NotGiven,
+)
from .._utils import maybe_transform
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper
-from .._base_client import make_request_options
+from .._base_client import (
+ make_request_options,
+)
if TYPE_CHECKING:
from .._client import Finch, AsyncFinch
diff --git a/src/finch/resources/webhooks.py b/src/finch/resources/webhooks.py
index 13b88d61..2ef89a80 100644
--- a/src/finch/resources/webhooks.py
+++ b/src/finch/resources/webhooks.py
@@ -10,8 +10,12 @@
from typing import TYPE_CHECKING
from datetime import datetime, timezone, timedelta
-from .._types import HeadersLike
-from .._utils import get_required_header
+from .._types import (
+ HeadersLike,
+)
+from .._utils import (
+ get_required_header,
+)
from .._resource import SyncAPIResource, AsyncAPIResource
if TYPE_CHECKING:
diff --git a/src/finch/types/__init__.py b/src/finch/types/__init__.py
index f6a15f80..cbf77492 100644
--- a/src/finch/types/__init__.py
+++ b/src/finch/types/__init__.py
@@ -4,9 +4,11 @@
from .money import Money as Money
from .income import Income as Income
-from .shared import Paging as Paging
-from .shared import OperationSupport as OperationSupport
-from .shared import OperationSupportMatrix as OperationSupportMatrix
+from .shared import (
+ Paging as Paging,
+ OperationSupport as OperationSupport,
+ OperationSupportMatrix as OperationSupportMatrix,
+)
from .location import Location as Location
from .provider import Provider as Provider
from .introspection import Introspection as Introspection
diff --git a/src/finch/types/hris/__init__.py b/src/finch/types/hris/__init__.py
index da28d4a5..0234b44b 100644
--- a/src/finch/types/hris/__init__.py
+++ b/src/finch/types/hris/__init__.py
@@ -23,27 +23,11 @@
from .individual_in_directory import IndividualInDirectory as IndividualInDirectory
from .employment_data_response import EmploymentDataResponse as EmploymentDataResponse
from .support_per_benefit_type import SupportPerBenefitType as SupportPerBenefitType
-from .pay_statement_response_body import (
- PayStatementResponseBody as PayStatementResponseBody,
-)
-from .benefit_features_and_operations import (
- BenefitFeaturesAndOperations as BenefitFeaturesAndOperations,
-)
-from .employment_retrieve_many_params import (
- EmploymentRetrieveManyParams as EmploymentRetrieveManyParams,
-)
-from .individual_retrieve_many_params import (
- IndividualRetrieveManyParams as IndividualRetrieveManyParams,
-)
-from .update_company_benefit_response import (
- UpdateCompanyBenefitResponse as UpdateCompanyBenefitResponse,
-)
-from .create_company_benefits_response import (
- CreateCompanyBenefitsResponse as CreateCompanyBenefitsResponse,
-)
-from .directory_list_individuals_params import (
- DirectoryListIndividualsParams as DirectoryListIndividualsParams,
-)
-from .pay_statement_retrieve_many_params import (
- PayStatementRetrieveManyParams as PayStatementRetrieveManyParams,
-)
+from .pay_statement_response_body import PayStatementResponseBody as PayStatementResponseBody
+from .benefit_features_and_operations import BenefitFeaturesAndOperations as BenefitFeaturesAndOperations
+from .employment_retrieve_many_params import EmploymentRetrieveManyParams as EmploymentRetrieveManyParams
+from .individual_retrieve_many_params import IndividualRetrieveManyParams as IndividualRetrieveManyParams
+from .update_company_benefit_response import UpdateCompanyBenefitResponse as UpdateCompanyBenefitResponse
+from .create_company_benefits_response import CreateCompanyBenefitsResponse as CreateCompanyBenefitsResponse
+from .directory_list_individuals_params import DirectoryListIndividualsParams as DirectoryListIndividualsParams
+from .pay_statement_retrieve_many_params import PayStatementRetrieveManyParams as PayStatementRetrieveManyParams
diff --git a/src/finch/types/hris/benefits/__init__.py b/src/finch/types/hris/benefits/__init__.py
index dc686ea2..0d548269 100644
--- a/src/finch/types/hris/benefits/__init__.py
+++ b/src/finch/types/hris/benefits/__init__.py
@@ -5,15 +5,9 @@
from .individual_benefit import IndividualBenefit as IndividualBenefit
from .enrolled_individual import EnrolledIndividual as EnrolledIndividual
from .unenrolled_individual import UnenrolledIndividual as UnenrolledIndividual
-from .individual_enroll_many_params import (
- IndividualEnrollManyParams as IndividualEnrollManyParams,
-)
-from .individual_unenroll_many_params import (
- IndividualUnenrollManyParams as IndividualUnenrollManyParams,
-)
-from .individual_enrolled_ids_response import (
- IndividualEnrolledIDsResponse as IndividualEnrolledIDsResponse,
-)
+from .individual_enroll_many_params import IndividualEnrollManyParams as IndividualEnrollManyParams
+from .individual_unenroll_many_params import IndividualUnenrollManyParams as IndividualUnenrollManyParams
+from .individual_enrolled_ids_response import IndividualEnrolledIDsResponse as IndividualEnrolledIDsResponse
from .individual_retrieve_many_benefits_params import (
IndividualRetrieveManyBenefitsParams as IndividualRetrieveManyBenefitsParams,
)
diff --git a/src/finch/types/hris/benfit_contribution.py b/src/finch/types/hris/benfit_contribution.py
index 676c3b8e..b3bee5cb 100644
--- a/src/finch/types/hris/benfit_contribution.py
+++ b/src/finch/types/hris/benfit_contribution.py
@@ -1,5 +1,7 @@
# File generated from our OpenAPI spec by Stainless.
+
+
from .benefit_contribution import BenefitContribution
BenfitContribution = BenefitContribution
diff --git a/src/finch/types/jobs/__init__.py b/src/finch/types/jobs/__init__.py
index 25ad24cf..b0470846 100644
--- a/src/finch/types/jobs/__init__.py
+++ b/src/finch/types/jobs/__init__.py
@@ -6,6 +6,4 @@
from .automated_async_job import AutomatedAsyncJob as AutomatedAsyncJob
from .automated_list_params import AutomatedListParams as AutomatedListParams
from .automated_create_params import AutomatedCreateParams as AutomatedCreateParams
-from .automated_create_response import (
- AutomatedCreateResponse as AutomatedCreateResponse,
-)
+from .automated_create_response import AutomatedCreateResponse as AutomatedCreateResponse
diff --git a/tests/utils.py b/tests/utils.py
index bc62203d..2dc9c0da 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -8,7 +8,12 @@
from typing_extensions import Literal, get_args, get_origin, assert_type
from finch._types import NoneType
-from finch._utils import is_dict, is_list, is_list_type, is_union_type
+from finch._utils import (
+ is_dict,
+ is_list,
+ is_list_type,
+ is_union_type,
+)
from finch._compat import PYDANTIC_V2, field_outer_type, get_model_fields
from finch._models import BaseModel
From cd5253c9a8417eec88dc8c30fdfa817ec1519a9e Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Thu, 7 Dec 2023 10:56:43 +0000
Subject: [PATCH 14/26] chore(internal): update formatting (#214)
---
src/finch/_client.py | 5 ++++-
src/finch/types/__init__.py | 8 ++------
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/finch/_client.py b/src/finch/_client.py
index 01252f1f..3c3b9636 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -22,7 +22,10 @@
AsyncTransport,
RequestOptions,
)
-from ._utils import is_given, get_async_library
+from ._utils import (
+ is_given,
+ get_async_library,
+)
from ._version import __version__
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
from ._exceptions import APIStatusError
diff --git a/src/finch/types/__init__.py b/src/finch/types/__init__.py
index cbf77492..ece2573d 100644
--- a/src/finch/types/__init__.py
+++ b/src/finch/types/__init__.py
@@ -13,9 +13,5 @@
from .provider import Provider as Provider
from .introspection import Introspection as Introspection
from .disconnect_response import DisconnectResponse as DisconnectResponse
-from .request_forwarding_forward_params import (
- RequestForwardingForwardParams as RequestForwardingForwardParams,
-)
-from .request_forwarding_forward_response import (
- RequestForwardingForwardResponse as RequestForwardingForwardResponse,
-)
+from .request_forwarding_forward_params import RequestForwardingForwardParams as RequestForwardingForwardParams
+from .request_forwarding_forward_response import RequestForwardingForwardResponse as RequestForwardingForwardResponse
From 9adf490d6b23ddb642eb630be867690a8f8a8693 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Thu, 7 Dec 2023 14:35:20 +0000
Subject: [PATCH 15/26] feat(pagination): remove unused types (#215)
---
src/finch/pagination.py | 108 ++++++++++++++++++++++++++--------------
1 file changed, 70 insertions(+), 38 deletions(-)
diff --git a/src/finch/pagination.py b/src/finch/pagination.py
index 38caea48..cd513eb1 100644
--- a/src/finch/pagination.py
+++ b/src/finch/pagination.py
@@ -30,7 +30,10 @@ class SyncSinglePage(BaseSyncPage[ModelT], BasePage[ModelT], Generic[ModelT]):
@override
def _get_page_items(self) -> List[ModelT]:
- return self.items
+ items = self.items
+ if not items:
+ return []
+ return items
@override
def next_page_info(self) -> None:
@@ -55,7 +58,10 @@ class AsyncSinglePage(BaseAsyncPage[ModelT], BasePage[ModelT], Generic[ModelT]):
@override
def _get_page_items(self) -> List[ModelT]:
- return self.items
+ items = self.items
+ if not items:
+ return []
+ return items
@override
def next_page_info(self) -> None:
@@ -80,7 +86,10 @@ class SyncResponsesPage(BaseSyncPage[ModelT], BasePage[ModelT], Generic[ModelT])
@override
def _get_page_items(self) -> List[ModelT]:
- return self.responses
+ responses = self.responses
+ if not responses:
+ return []
+ return responses
@override
def next_page_info(self) -> None:
@@ -96,7 +105,10 @@ class AsyncResponsesPage(BaseAsyncPage[ModelT], BasePage[ModelT], Generic[ModelT
@override
def _get_page_items(self) -> List[ModelT]:
- return self.responses
+ responses = self.responses
+ if not responses:
+ return []
+ return responses
@override
def next_page_info(self) -> None:
@@ -107,32 +119,35 @@ def next_page_info(self) -> None:
return None
-IndividualsPagePaging = Paging
-"""This is deprecated, Paging should be used instead"""
-
-
class SyncIndividualsPage(BaseSyncPage[ModelT], BasePage[ModelT], Generic[ModelT]):
individuals: List[ModelT]
paging: Paging
@override
def _get_page_items(self) -> List[ModelT]:
- return self.individuals
+ individuals = self.individuals
+ if not individuals:
+ return []
+ return individuals
@override
def next_page_info(self) -> Optional[PageInfo]:
- offset = self.paging.offset
+ offset = None
+ if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison]
+ offset = self.paging.offset
if offset is None:
return None
- length = len(self.individuals)
+ length = len(self._get_page_items())
current_count = offset + length
- total_count = self.paging.count
- if total_count is None:
+ count = None
+ if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison]
+ count = self.paging.count
+ if count is None:
return None
- if current_count < total_count:
+ if current_count < count:
return PageInfo(params={"offset": current_count})
return None
@@ -144,80 +159,97 @@ class AsyncIndividualsPage(BaseAsyncPage[ModelT], BasePage[ModelT], Generic[Mode
@override
def _get_page_items(self) -> List[ModelT]:
- return self.individuals
+ individuals = self.individuals
+ if not individuals:
+ return []
+ return individuals
@override
def next_page_info(self) -> Optional[PageInfo]:
- offset = self.paging.offset
+ offset = None
+ if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison]
+ offset = self.paging.offset
if offset is None:
return None
- length = len(self.individuals)
+ length = len(self._get_page_items())
current_count = offset + length
- total_count = self.paging.count
- if total_count is None:
+ count = None
+ if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison]
+ count = self.paging.count
+ if count is None:
return None
- if current_count < total_count:
+ if current_count < count:
return PageInfo(params={"offset": current_count})
return None
-PagePaging = Paging
-"""This is deprecated, Paging should be used instead"""
-
-
class SyncPage(BaseSyncPage[ModelT], BasePage[ModelT], Generic[ModelT]):
- paging: Paging
data: List[ModelT]
+ paging: Paging
@override
def _get_page_items(self) -> List[ModelT]:
- return self.data
+ data = self.data
+ if not data:
+ return []
+ return data
@override
def next_page_info(self) -> Optional[PageInfo]:
- offset = self.paging.offset
+ offset = None
+ if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison]
+ offset = self.paging.offset
if offset is None:
return None
- length = len(self.data)
+ length = len(self._get_page_items())
current_count = offset + length
- total_count = self.paging.count
- if total_count is None:
+ count = None
+ if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison]
+ count = self.paging.count
+ if count is None:
return None
- if current_count < total_count:
+ if current_count < count:
return PageInfo(params={"offset": current_count})
return None
class AsyncPage(BaseAsyncPage[ModelT], BasePage[ModelT], Generic[ModelT]):
- paging: Paging
data: List[ModelT]
+ paging: Paging
@override
def _get_page_items(self) -> List[ModelT]:
- return self.data
+ data = self.data
+ if not data:
+ return []
+ return data
@override
def next_page_info(self) -> Optional[PageInfo]:
- offset = self.paging.offset
+ offset = None
+ if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison]
+ offset = self.paging.offset
if offset is None:
return None
- length = len(self.data)
+ length = len(self._get_page_items())
current_count = offset + length
- total_count = self.paging.count
- if total_count is None:
+ count = None
+ if self.paging is not None: # pyright: ignore[reportUnnecessaryComparison]
+ count = self.paging.count
+ if count is None:
return None
- if current_count < total_count:
+ if current_count < count:
return PageInfo(params={"offset": current_count})
return None
From 14c8df00568bba59acab45ff6cdef2cb04599b43 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Thu, 7 Dec 2023 14:55:37 +0000
Subject: [PATCH 16/26] chore(internal): reformat imports (#216)
---
pyproject.toml | 37 +++++----
requirements-dev.lock | 3 +-
src/finch/_client.py | 8 +-
src/finch/_compat.py | 30 ++++----
src/finch/_models.py | 14 +++-
src/finch/_types.py | 9 ++-
src/finch/_utils/__init__.py | 76 +++++++++----------
src/finch/_utils/_utils.py | 4 +-
src/finch/resources/__init__.py | 14 +++-
src/finch/resources/account.py | 12 +--
src/finch/resources/hris/__init__.py | 35 +++++++--
src/finch/resources/hris/benefits/__init__.py | 14 +++-
src/finch/resources/hris/benefits/benefits.py | 20 ++---
.../resources/hris/benefits/individuals.py | 13 +---
src/finch/resources/hris/company.py | 12 +--
src/finch/resources/hris/directory.py | 18 +----
src/finch/resources/hris/employments.py | 13 +---
src/finch/resources/hris/hris.py | 35 +++++++--
src/finch/resources/hris/individuals.py | 13 +---
src/finch/resources/hris/pay_statements.py | 13 +---
src/finch/resources/hris/payments.py | 13 +---
src/finch/resources/jobs/__init__.py | 14 +++-
src/finch/resources/jobs/automated.py | 13 +---
src/finch/resources/jobs/jobs.py | 14 +++-
src/finch/resources/jobs/manual.py | 12 +--
src/finch/resources/providers.py | 13 +---
src/finch/resources/request_forwarding.py | 17 +----
src/finch/resources/webhooks.py | 8 +-
src/finch/types/__init__.py | 16 ++--
src/finch/types/hris/__init__.py | 32 ++++++--
src/finch/types/hris/benefits/__init__.py | 12 ++-
src/finch/types/hris/benfit_contribution.py | 2 -
src/finch/types/jobs/__init__.py | 4 +-
tests/utils.py | 7 +-
34 files changed, 284 insertions(+), 286 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 59fcb8e2..b831f420 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -46,16 +46,16 @@ Repository = "https://github.com/Finch-API/finch-api-python"
[tool.rye]
managed = true
dev-dependencies = [
- # version pins are in requirements-dev.lock
- "pyright",
- "mypy",
- "black",
- "respx",
- "pytest",
- "pytest-asyncio",
- "ruff",
- "time-machine",
- "nox",
+ "pyright==1.1.332",
+ "mypy==1.7.1",
+ "black==23.3.0",
+ "respx==0.20.2",
+ "pytest==7.1.1",
+ "pytest-asyncio==0.21.1",
+ "ruff==0.0.282",
+ "isort==5.10.1",
+ "time-machine==2.9.0",
+ "nox==2023.4.22",
"dirty-equals>=0.6.0",
]
@@ -65,10 +65,12 @@ format = { chain = [
"format:black",
"format:docs",
"format:ruff",
+ "format:isort",
]}
"format:black" = "black ."
"format:docs" = "python bin/blacken-docs.py README.md api.md"
"format:ruff" = "ruff --fix ."
+"format:isort" = "isort ."
"check:ruff" = "ruff ."
@@ -123,13 +125,16 @@ reportImplicitOverride = true
reportImportCycles = false
reportPrivateUsage = false
+[tool.isort]
+profile = "black"
+length_sort = true
+extra_standard_library = ["typing_extensions"]
+
[tool.ruff]
line-length = 120
-output-format = "grouped"
+format = "grouped"
target-version = "py37"
select = [
- # isort
- "I",
# remove unused imports
"F401",
# bare except statements
@@ -147,12 +152,6 @@ unfixable = [
]
ignore-init-module-imports = true
-[tool.ruff.lint.isort]
-length-sort = true
-length-sort-straight = true
-combine-as-imports = true
-extra-standard-library = ["typing_extensions"]
-known-first-party = ["finch", "tests"]
[tool.ruff.per-file-ignores]
"bin/**.py" = ["T201", "T203"]
diff --git a/requirements-dev.lock b/requirements-dev.lock
index 36843262..ce154682 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -25,6 +25,7 @@ httpcore==1.0.2
httpx==0.25.2
idna==3.4
iniconfig==2.0.0
+isort==5.10.1
mypy==1.7.1
mypy-extensions==1.0.0
nodeenv==1.8.0
@@ -42,7 +43,7 @@ pytest-asyncio==0.21.1
python-dateutil==2.8.2
pytz==2023.3.post1
respx==0.20.2
-ruff==0.1.7
+ruff==0.0.282
six==1.16.0
sniffio==1.3.0
time-machine==2.9.0
diff --git a/src/finch/_client.py b/src/finch/_client.py
index 3c3b9636..149406a0 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -22,12 +22,10 @@
AsyncTransport,
RequestOptions,
)
-from ._utils import (
- is_given,
- get_async_library,
-)
+from ._utils import is_given, get_async_library
from ._version import __version__
-from ._streaming import Stream as Stream, AsyncStream as AsyncStream
+from ._streaming import Stream as Stream
+from ._streaming import AsyncStream as AsyncStream
from ._exceptions import APIStatusError
from ._base_client import (
DEFAULT_LIMITS,
diff --git a/src/finch/_compat.py b/src/finch/_compat.py
index d95db8ed..34323c9b 100644
--- a/src/finch/_compat.py
+++ b/src/finch/_compat.py
@@ -43,23 +43,21 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001
else:
if PYDANTIC_V2:
- from pydantic.v1.typing import (
- get_args as get_args,
- is_union as is_union,
- get_origin as get_origin,
- is_typeddict as is_typeddict,
- is_literal_type as is_literal_type,
- )
- from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
+ from pydantic.v1.typing import get_args as get_args
+ from pydantic.v1.typing import is_union as is_union
+ from pydantic.v1.typing import get_origin as get_origin
+ from pydantic.v1.typing import is_typeddict as is_typeddict
+ from pydantic.v1.typing import is_literal_type as is_literal_type
+ from pydantic.v1.datetime_parse import parse_date as parse_date
+ from pydantic.v1.datetime_parse import parse_datetime as parse_datetime
else:
- from pydantic.typing import (
- get_args as get_args,
- is_union as is_union,
- get_origin as get_origin,
- is_typeddict as is_typeddict,
- is_literal_type as is_literal_type,
- )
- from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
+ from pydantic.typing import get_args as get_args
+ from pydantic.typing import is_union as is_union
+ from pydantic.typing import get_origin as get_origin
+ from pydantic.typing import is_typeddict as is_typeddict
+ from pydantic.typing import is_literal_type as is_literal_type
+ from pydantic.datetime_parse import parse_date as parse_date
+ from pydantic.datetime_parse import parse_datetime as parse_datetime
# refactored config
diff --git a/src/finch/_models.py b/src/finch/_models.py
index cdd44ccb..5b8c9601 100644
--- a/src/finch/_models.py
+++ b/src/finch/_models.py
@@ -30,11 +30,17 @@
AnyMapping,
HttpxRequestFiles,
)
-from ._utils import is_list, is_given, is_mapping, parse_date, parse_datetime, strip_not_given
+from ._utils import (
+ is_list,
+ is_given,
+ is_mapping,
+ parse_date,
+ parse_datetime,
+ strip_not_given,
+)
+from ._compat import PYDANTIC_V2, ConfigDict
+from ._compat import GenericModel as BaseGenericModel
from ._compat import (
- PYDANTIC_V2,
- ConfigDict,
- GenericModel as BaseGenericModel,
get_args,
is_union,
parse_obj,
diff --git a/src/finch/_types.py b/src/finch/_types.py
index 7f82cf4a..e12f064d 100644
--- a/src/finch/_types.py
+++ b/src/finch/_types.py
@@ -19,7 +19,14 @@
Sequence,
AsyncIterator,
)
-from typing_extensions import Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable
+from typing_extensions import (
+ Literal,
+ Protocol,
+ TypeAlias,
+ TypedDict,
+ override,
+ runtime_checkable,
+)
import pydantic
from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport
diff --git a/src/finch/_utils/__init__.py b/src/finch/_utils/__init__.py
index e98636c9..400ca9b8 100644
--- a/src/finch/_utils/__init__.py
+++ b/src/finch/_utils/__init__.py
@@ -1,41 +1,37 @@
from ._proxy import LazyProxy as LazyProxy
-from ._utils import (
- flatten as flatten,
- is_dict as is_dict,
- is_list as is_list,
- is_given as is_given,
- is_tuple as is_tuple,
- is_mapping as is_mapping,
- is_tuple_t as is_tuple_t,
- parse_date as parse_date,
- is_sequence as is_sequence,
- coerce_float as coerce_float,
- is_list_type as is_list_type,
- is_mapping_t as is_mapping_t,
- removeprefix as removeprefix,
- removesuffix as removesuffix,
- extract_files as extract_files,
- is_sequence_t as is_sequence_t,
- is_union_type as is_union_type,
- required_args as required_args,
- coerce_boolean as coerce_boolean,
- coerce_integer as coerce_integer,
- file_from_path as file_from_path,
- parse_datetime as parse_datetime,
- strip_not_given as strip_not_given,
- deepcopy_minimal as deepcopy_minimal,
- extract_type_arg as extract_type_arg,
- is_required_type as is_required_type,
- get_async_library as get_async_library,
- is_annotated_type as is_annotated_type,
- maybe_coerce_float as maybe_coerce_float,
- get_required_header as get_required_header,
- maybe_coerce_boolean as maybe_coerce_boolean,
- maybe_coerce_integer as maybe_coerce_integer,
- strip_annotated_type as strip_annotated_type,
-)
-from ._transform import (
- PropertyInfo as PropertyInfo,
- transform as transform,
- maybe_transform as maybe_transform,
-)
+from ._utils import flatten as flatten
+from ._utils import is_dict as is_dict
+from ._utils import is_list as is_list
+from ._utils import is_given as is_given
+from ._utils import is_tuple as is_tuple
+from ._utils import is_mapping as is_mapping
+from ._utils import is_tuple_t as is_tuple_t
+from ._utils import parse_date as parse_date
+from ._utils import is_sequence as is_sequence
+from ._utils import coerce_float as coerce_float
+from ._utils import is_list_type as is_list_type
+from ._utils import is_mapping_t as is_mapping_t
+from ._utils import removeprefix as removeprefix
+from ._utils import removesuffix as removesuffix
+from ._utils import extract_files as extract_files
+from ._utils import is_sequence_t as is_sequence_t
+from ._utils import is_union_type as is_union_type
+from ._utils import required_args as required_args
+from ._utils import coerce_boolean as coerce_boolean
+from ._utils import coerce_integer as coerce_integer
+from ._utils import file_from_path as file_from_path
+from ._utils import parse_datetime as parse_datetime
+from ._utils import strip_not_given as strip_not_given
+from ._utils import deepcopy_minimal as deepcopy_minimal
+from ._utils import extract_type_arg as extract_type_arg
+from ._utils import is_required_type as is_required_type
+from ._utils import get_async_library as get_async_library
+from ._utils import is_annotated_type as is_annotated_type
+from ._utils import maybe_coerce_float as maybe_coerce_float
+from ._utils import get_required_header as get_required_header
+from ._utils import maybe_coerce_boolean as maybe_coerce_boolean
+from ._utils import maybe_coerce_integer as maybe_coerce_integer
+from ._utils import strip_annotated_type as strip_annotated_type
+from ._transform import PropertyInfo as PropertyInfo
+from ._transform import transform as transform
+from ._transform import maybe_transform as maybe_transform
diff --git a/src/finch/_utils/_utils.py b/src/finch/_utils/_utils.py
index cce69238..83f88cc3 100644
--- a/src/finch/_utils/_utils.py
+++ b/src/finch/_utils/_utils.py
@@ -21,7 +21,9 @@
import sniffio
from .._types import Headers, NotGiven, FileTypes, NotGivenOr, HeadersLike
-from .._compat import is_union as _is_union, parse_date as parse_date, parse_datetime as parse_datetime
+from .._compat import is_union as _is_union
+from .._compat import parse_date as parse_date
+from .._compat import parse_datetime as parse_datetime
_T = TypeVar("_T")
_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...])
diff --git a/src/finch/resources/__init__.py b/src/finch/resources/__init__.py
index 32d0cf28..dcab5333 100644
--- a/src/finch/resources/__init__.py
+++ b/src/finch/resources/__init__.py
@@ -2,9 +2,19 @@
from .hris import HRIS, AsyncHRIS, HRISWithRawResponse, AsyncHRISWithRawResponse
from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse
-from .account import Account, AsyncAccount, AccountWithRawResponse, AsyncAccountWithRawResponse
+from .account import (
+ Account,
+ AsyncAccount,
+ AccountWithRawResponse,
+ AsyncAccountWithRawResponse,
+)
from .webhooks import Webhooks, AsyncWebhooks
-from .providers import Providers, AsyncProviders, ProvidersWithRawResponse, AsyncProvidersWithRawResponse
+from .providers import (
+ Providers,
+ AsyncProviders,
+ ProvidersWithRawResponse,
+ AsyncProvidersWithRawResponse,
+)
from .request_forwarding import (
RequestForwarding,
AsyncRequestForwarding,
diff --git a/src/finch/resources/account.py b/src/finch/resources/account.py
index 0cb7b3aa..5d90dfdc 100644
--- a/src/finch/resources/account.py
+++ b/src/finch/resources/account.py
@@ -7,18 +7,10 @@
import httpx
from ..types import Introspection, DisconnectResponse
-from .._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper
-from .._base_client import (
- make_request_options,
-)
+from .._base_client import make_request_options
if TYPE_CHECKING:
from .._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/__init__.py b/src/finch/resources/hris/__init__.py
index 8f292e8f..4659abb9 100644
--- a/src/finch/resources/hris/__init__.py
+++ b/src/finch/resources/hris/__init__.py
@@ -7,11 +7,36 @@
CompanyResourceWithRawResponse,
AsyncCompanyResourceWithRawResponse,
)
-from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse
-from .payments import Payments, AsyncPayments, PaymentsWithRawResponse, AsyncPaymentsWithRawResponse
-from .directory import Directory, AsyncDirectory, DirectoryWithRawResponse, AsyncDirectoryWithRawResponse
-from .employments import Employments, AsyncEmployments, EmploymentsWithRawResponse, AsyncEmploymentsWithRawResponse
-from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse
+from .benefits import (
+ Benefits,
+ AsyncBenefits,
+ BenefitsWithRawResponse,
+ AsyncBenefitsWithRawResponse,
+)
+from .payments import (
+ Payments,
+ AsyncPayments,
+ PaymentsWithRawResponse,
+ AsyncPaymentsWithRawResponse,
+)
+from .directory import (
+ Directory,
+ AsyncDirectory,
+ DirectoryWithRawResponse,
+ AsyncDirectoryWithRawResponse,
+)
+from .employments import (
+ Employments,
+ AsyncEmployments,
+ EmploymentsWithRawResponse,
+ AsyncEmploymentsWithRawResponse,
+)
+from .individuals import (
+ Individuals,
+ AsyncIndividuals,
+ IndividualsWithRawResponse,
+ AsyncIndividualsWithRawResponse,
+)
from .pay_statements import (
PayStatements,
AsyncPayStatements,
diff --git a/src/finch/resources/hris/benefits/__init__.py b/src/finch/resources/hris/benefits/__init__.py
index 9a5b9063..fbbe99ea 100644
--- a/src/finch/resources/hris/benefits/__init__.py
+++ b/src/finch/resources/hris/benefits/__init__.py
@@ -1,7 +1,17 @@
# File generated from our OpenAPI spec by Stainless.
-from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse
-from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse
+from .benefits import (
+ Benefits,
+ AsyncBenefits,
+ BenefitsWithRawResponse,
+ AsyncBenefitsWithRawResponse,
+)
+from .individuals import (
+ Individuals,
+ AsyncIndividuals,
+ IndividualsWithRawResponse,
+ AsyncIndividualsWithRawResponse,
+)
__all__ = [
"Individuals",
diff --git a/src/finch/resources/hris/benefits/benefits.py b/src/finch/resources/hris/benefits/benefits.py
index 4752a838..f90a5100 100644
--- a/src/finch/resources/hris/benefits/benefits.py
+++ b/src/finch/resources/hris/benefits/benefits.py
@@ -6,15 +6,14 @@
import httpx
-from ...._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ...._utils import maybe_transform
-from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse
+from .individuals import (
+ Individuals,
+ AsyncIndividuals,
+ IndividualsWithRawResponse,
+ AsyncIndividualsWithRawResponse,
+)
from ...._resource import SyncAPIResource, AsyncAPIResource
from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ....pagination import SyncSinglePage, AsyncSinglePage
@@ -28,10 +27,7 @@
benefit_create_params,
benefit_update_params,
)
-from ...._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from ...._base_client import AsyncPaginator, make_request_options
if TYPE_CHECKING:
from ...._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/benefits/individuals.py b/src/finch/resources/hris/benefits/individuals.py
index cb09ddf4..fb4b3450 100644
--- a/src/finch/resources/hris/benefits/individuals.py
+++ b/src/finch/resources/hris/benefits/individuals.py
@@ -6,21 +6,12 @@
import httpx
-from ...._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ...._utils import maybe_transform
from ...._resource import SyncAPIResource, AsyncAPIResource
from ...._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ....pagination import SyncSinglePage, AsyncSinglePage
-from ...._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from ...._base_client import AsyncPaginator, make_request_options
from ....types.hris.benefits import (
IndividualBenefit,
EnrolledIndividual,
diff --git a/src/finch/resources/hris/company.py b/src/finch/resources/hris/company.py
index 3ee67da7..af6d6441 100644
--- a/src/finch/resources/hris/company.py
+++ b/src/finch/resources/hris/company.py
@@ -6,19 +6,11 @@
import httpx
-from ..._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...types.hris import Company
-from ..._base_client import (
- make_request_options,
-)
+from ..._base_client import make_request_options
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/directory.py b/src/finch/resources/hris/directory.py
index 221586f6..ff3950aa 100644
--- a/src/finch/resources/hris/directory.py
+++ b/src/finch/resources/hris/directory.py
@@ -7,25 +7,13 @@
import httpx
-from ..._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncIndividualsPage, AsyncIndividualsPage
-from ...types.hris import (
- IndividualInDirectory,
- directory_list_params,
-)
-from ..._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from ...types.hris import IndividualInDirectory, directory_list_params
+from ..._base_client import AsyncPaginator, make_request_options
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/employments.py b/src/finch/resources/hris/employments.py
index c0bd79ba..0b16202e 100644
--- a/src/finch/resources/hris/employments.py
+++ b/src/finch/resources/hris/employments.py
@@ -6,22 +6,13 @@
import httpx
-from ..._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncResponsesPage, AsyncResponsesPage
from ...types.hris import EmploymentDataResponse, employment_retrieve_many_params
-from ..._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from ..._base_client import AsyncPaginator, make_request_options
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/hris.py b/src/finch/resources/hris/hris.py
index 0ba66160..8cd4f554 100644
--- a/src/finch/resources/hris/hris.py
+++ b/src/finch/resources/hris/hris.py
@@ -10,12 +10,37 @@
CompanyResourceWithRawResponse,
AsyncCompanyResourceWithRawResponse,
)
-from .benefits import Benefits, AsyncBenefits, BenefitsWithRawResponse, AsyncBenefitsWithRawResponse
-from .payments import Payments, AsyncPayments, PaymentsWithRawResponse, AsyncPaymentsWithRawResponse
-from .directory import Directory, AsyncDirectory, DirectoryWithRawResponse, AsyncDirectoryWithRawResponse
+from .benefits import (
+ Benefits,
+ AsyncBenefits,
+ BenefitsWithRawResponse,
+ AsyncBenefitsWithRawResponse,
+)
+from .payments import (
+ Payments,
+ AsyncPayments,
+ PaymentsWithRawResponse,
+ AsyncPaymentsWithRawResponse,
+)
+from .directory import (
+ Directory,
+ AsyncDirectory,
+ DirectoryWithRawResponse,
+ AsyncDirectoryWithRawResponse,
+)
from ..._resource import SyncAPIResource, AsyncAPIResource
-from .employments import Employments, AsyncEmployments, EmploymentsWithRawResponse, AsyncEmploymentsWithRawResponse
-from .individuals import Individuals, AsyncIndividuals, IndividualsWithRawResponse, AsyncIndividualsWithRawResponse
+from .employments import (
+ Employments,
+ AsyncEmployments,
+ EmploymentsWithRawResponse,
+ AsyncEmploymentsWithRawResponse,
+)
+from .individuals import (
+ Individuals,
+ AsyncIndividuals,
+ IndividualsWithRawResponse,
+ AsyncIndividualsWithRawResponse,
+)
from .pay_statements import (
PayStatements,
AsyncPayStatements,
diff --git a/src/finch/resources/hris/individuals.py b/src/finch/resources/hris/individuals.py
index 8ca24125..892eb820 100644
--- a/src/finch/resources/hris/individuals.py
+++ b/src/finch/resources/hris/individuals.py
@@ -6,22 +6,13 @@
import httpx
-from ..._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncResponsesPage, AsyncResponsesPage
from ...types.hris import IndividualResponse, individual_retrieve_many_params
-from ..._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from ..._base_client import AsyncPaginator, make_request_options
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/pay_statements.py b/src/finch/resources/hris/pay_statements.py
index 6ad4be76..4c444e9b 100644
--- a/src/finch/resources/hris/pay_statements.py
+++ b/src/finch/resources/hris/pay_statements.py
@@ -6,22 +6,13 @@
import httpx
-from ..._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncResponsesPage, AsyncResponsesPage
from ...types.hris import PayStatementResponse, pay_statement_retrieve_many_params
-from ..._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from ..._base_client import AsyncPaginator, make_request_options
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/hris/payments.py b/src/finch/resources/hris/payments.py
index d5d0b28d..17364d80 100644
--- a/src/finch/resources/hris/payments.py
+++ b/src/finch/resources/hris/payments.py
@@ -7,22 +7,13 @@
import httpx
-from ..._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...pagination import SyncSinglePage, AsyncSinglePage
from ...types.hris import Payment, payment_list_params
-from ..._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from ..._base_client import AsyncPaginator, make_request_options
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/jobs/__init__.py b/src/finch/resources/jobs/__init__.py
index 112d3130..f1f7692d 100644
--- a/src/finch/resources/jobs/__init__.py
+++ b/src/finch/resources/jobs/__init__.py
@@ -1,8 +1,18 @@
# File generated from our OpenAPI spec by Stainless.
from .jobs import Jobs, AsyncJobs, JobsWithRawResponse, AsyncJobsWithRawResponse
-from .manual import Manual, AsyncManual, ManualWithRawResponse, AsyncManualWithRawResponse
-from .automated import Automated, AsyncAutomated, AutomatedWithRawResponse, AsyncAutomatedWithRawResponse
+from .manual import (
+ Manual,
+ AsyncManual,
+ ManualWithRawResponse,
+ AsyncManualWithRawResponse,
+)
+from .automated import (
+ Automated,
+ AsyncAutomated,
+ AutomatedWithRawResponse,
+ AsyncAutomatedWithRawResponse,
+)
__all__ = [
"Automated",
diff --git a/src/finch/resources/jobs/automated.py b/src/finch/resources/jobs/automated.py
index 48f2199b..9f43c60a 100644
--- a/src/finch/resources/jobs/automated.py
+++ b/src/finch/resources/jobs/automated.py
@@ -7,13 +7,7 @@
import httpx
-from ..._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._utils import maybe_transform
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
@@ -24,10 +18,7 @@
automated_list_params,
automated_create_params,
)
-from ..._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from ..._base_client import AsyncPaginator, make_request_options
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/jobs/jobs.py b/src/finch/resources/jobs/jobs.py
index a47c4ddd..f522c9c5 100644
--- a/src/finch/resources/jobs/jobs.py
+++ b/src/finch/resources/jobs/jobs.py
@@ -4,8 +4,18 @@
from typing import TYPE_CHECKING
-from .manual import Manual, AsyncManual, ManualWithRawResponse, AsyncManualWithRawResponse
-from .automated import Automated, AsyncAutomated, AutomatedWithRawResponse, AsyncAutomatedWithRawResponse
+from .manual import (
+ Manual,
+ AsyncManual,
+ ManualWithRawResponse,
+ AsyncManualWithRawResponse,
+)
+from .automated import (
+ Automated,
+ AsyncAutomated,
+ AutomatedWithRawResponse,
+ AsyncAutomatedWithRawResponse,
+)
from ..._resource import SyncAPIResource, AsyncAPIResource
if TYPE_CHECKING:
diff --git a/src/finch/resources/jobs/manual.py b/src/finch/resources/jobs/manual.py
index 61f16619..9334f2da 100644
--- a/src/finch/resources/jobs/manual.py
+++ b/src/finch/resources/jobs/manual.py
@@ -6,19 +6,11 @@
import httpx
-from ..._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ...types.jobs import ManualAsyncJob
-from ..._base_client import (
- make_request_options,
-)
+from ..._base_client import make_request_options
if TYPE_CHECKING:
from ..._client import Finch, AsyncFinch
diff --git a/src/finch/resources/providers.py b/src/finch/resources/providers.py
index 5f8b17c7..aa6eedc5 100644
--- a/src/finch/resources/providers.py
+++ b/src/finch/resources/providers.py
@@ -7,20 +7,11 @@
import httpx
from ..types import Provider
-from .._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from ..pagination import SyncSinglePage, AsyncSinglePage
-from .._base_client import (
- AsyncPaginator,
- make_request_options,
-)
+from .._base_client import AsyncPaginator, make_request_options
if TYPE_CHECKING:
from .._client import Finch, AsyncFinch
diff --git a/src/finch/resources/request_forwarding.py b/src/finch/resources/request_forwarding.py
index 4c571b39..2464bb35 100644
--- a/src/finch/resources/request_forwarding.py
+++ b/src/finch/resources/request_forwarding.py
@@ -6,23 +6,12 @@
import httpx
-from ..types import (
- RequestForwardingForwardResponse,
- request_forwarding_forward_params,
-)
-from .._types import (
- NOT_GIVEN,
- Body,
- Query,
- Headers,
- NotGiven,
-)
+from ..types import RequestForwardingForwardResponse, request_forwarding_forward_params
+from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._utils import maybe_transform
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper
-from .._base_client import (
- make_request_options,
-)
+from .._base_client import make_request_options
if TYPE_CHECKING:
from .._client import Finch, AsyncFinch
diff --git a/src/finch/resources/webhooks.py b/src/finch/resources/webhooks.py
index 2ef89a80..13b88d61 100644
--- a/src/finch/resources/webhooks.py
+++ b/src/finch/resources/webhooks.py
@@ -10,12 +10,8 @@
from typing import TYPE_CHECKING
from datetime import datetime, timezone, timedelta
-from .._types import (
- HeadersLike,
-)
-from .._utils import (
- get_required_header,
-)
+from .._types import HeadersLike
+from .._utils import get_required_header
from .._resource import SyncAPIResource, AsyncAPIResource
if TYPE_CHECKING:
diff --git a/src/finch/types/__init__.py b/src/finch/types/__init__.py
index ece2573d..f6a15f80 100644
--- a/src/finch/types/__init__.py
+++ b/src/finch/types/__init__.py
@@ -4,14 +4,16 @@
from .money import Money as Money
from .income import Income as Income
-from .shared import (
- Paging as Paging,
- OperationSupport as OperationSupport,
- OperationSupportMatrix as OperationSupportMatrix,
-)
+from .shared import Paging as Paging
+from .shared import OperationSupport as OperationSupport
+from .shared import OperationSupportMatrix as OperationSupportMatrix
from .location import Location as Location
from .provider import Provider as Provider
from .introspection import Introspection as Introspection
from .disconnect_response import DisconnectResponse as DisconnectResponse
-from .request_forwarding_forward_params import RequestForwardingForwardParams as RequestForwardingForwardParams
-from .request_forwarding_forward_response import RequestForwardingForwardResponse as RequestForwardingForwardResponse
+from .request_forwarding_forward_params import (
+ RequestForwardingForwardParams as RequestForwardingForwardParams,
+)
+from .request_forwarding_forward_response import (
+ RequestForwardingForwardResponse as RequestForwardingForwardResponse,
+)
diff --git a/src/finch/types/hris/__init__.py b/src/finch/types/hris/__init__.py
index 0234b44b..da28d4a5 100644
--- a/src/finch/types/hris/__init__.py
+++ b/src/finch/types/hris/__init__.py
@@ -23,11 +23,27 @@
from .individual_in_directory import IndividualInDirectory as IndividualInDirectory
from .employment_data_response import EmploymentDataResponse as EmploymentDataResponse
from .support_per_benefit_type import SupportPerBenefitType as SupportPerBenefitType
-from .pay_statement_response_body import PayStatementResponseBody as PayStatementResponseBody
-from .benefit_features_and_operations import BenefitFeaturesAndOperations as BenefitFeaturesAndOperations
-from .employment_retrieve_many_params import EmploymentRetrieveManyParams as EmploymentRetrieveManyParams
-from .individual_retrieve_many_params import IndividualRetrieveManyParams as IndividualRetrieveManyParams
-from .update_company_benefit_response import UpdateCompanyBenefitResponse as UpdateCompanyBenefitResponse
-from .create_company_benefits_response import CreateCompanyBenefitsResponse as CreateCompanyBenefitsResponse
-from .directory_list_individuals_params import DirectoryListIndividualsParams as DirectoryListIndividualsParams
-from .pay_statement_retrieve_many_params import PayStatementRetrieveManyParams as PayStatementRetrieveManyParams
+from .pay_statement_response_body import (
+ PayStatementResponseBody as PayStatementResponseBody,
+)
+from .benefit_features_and_operations import (
+ BenefitFeaturesAndOperations as BenefitFeaturesAndOperations,
+)
+from .employment_retrieve_many_params import (
+ EmploymentRetrieveManyParams as EmploymentRetrieveManyParams,
+)
+from .individual_retrieve_many_params import (
+ IndividualRetrieveManyParams as IndividualRetrieveManyParams,
+)
+from .update_company_benefit_response import (
+ UpdateCompanyBenefitResponse as UpdateCompanyBenefitResponse,
+)
+from .create_company_benefits_response import (
+ CreateCompanyBenefitsResponse as CreateCompanyBenefitsResponse,
+)
+from .directory_list_individuals_params import (
+ DirectoryListIndividualsParams as DirectoryListIndividualsParams,
+)
+from .pay_statement_retrieve_many_params import (
+ PayStatementRetrieveManyParams as PayStatementRetrieveManyParams,
+)
diff --git a/src/finch/types/hris/benefits/__init__.py b/src/finch/types/hris/benefits/__init__.py
index 0d548269..dc686ea2 100644
--- a/src/finch/types/hris/benefits/__init__.py
+++ b/src/finch/types/hris/benefits/__init__.py
@@ -5,9 +5,15 @@
from .individual_benefit import IndividualBenefit as IndividualBenefit
from .enrolled_individual import EnrolledIndividual as EnrolledIndividual
from .unenrolled_individual import UnenrolledIndividual as UnenrolledIndividual
-from .individual_enroll_many_params import IndividualEnrollManyParams as IndividualEnrollManyParams
-from .individual_unenroll_many_params import IndividualUnenrollManyParams as IndividualUnenrollManyParams
-from .individual_enrolled_ids_response import IndividualEnrolledIDsResponse as IndividualEnrolledIDsResponse
+from .individual_enroll_many_params import (
+ IndividualEnrollManyParams as IndividualEnrollManyParams,
+)
+from .individual_unenroll_many_params import (
+ IndividualUnenrollManyParams as IndividualUnenrollManyParams,
+)
+from .individual_enrolled_ids_response import (
+ IndividualEnrolledIDsResponse as IndividualEnrolledIDsResponse,
+)
from .individual_retrieve_many_benefits_params import (
IndividualRetrieveManyBenefitsParams as IndividualRetrieveManyBenefitsParams,
)
diff --git a/src/finch/types/hris/benfit_contribution.py b/src/finch/types/hris/benfit_contribution.py
index b3bee5cb..676c3b8e 100644
--- a/src/finch/types/hris/benfit_contribution.py
+++ b/src/finch/types/hris/benfit_contribution.py
@@ -1,7 +1,5 @@
# File generated from our OpenAPI spec by Stainless.
-
-
from .benefit_contribution import BenefitContribution
BenfitContribution = BenefitContribution
diff --git a/src/finch/types/jobs/__init__.py b/src/finch/types/jobs/__init__.py
index b0470846..25ad24cf 100644
--- a/src/finch/types/jobs/__init__.py
+++ b/src/finch/types/jobs/__init__.py
@@ -6,4 +6,6 @@
from .automated_async_job import AutomatedAsyncJob as AutomatedAsyncJob
from .automated_list_params import AutomatedListParams as AutomatedListParams
from .automated_create_params import AutomatedCreateParams as AutomatedCreateParams
-from .automated_create_response import AutomatedCreateResponse as AutomatedCreateResponse
+from .automated_create_response import (
+ AutomatedCreateResponse as AutomatedCreateResponse,
+)
diff --git a/tests/utils.py b/tests/utils.py
index 2dc9c0da..bc62203d 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -8,12 +8,7 @@
from typing_extensions import Literal, get_args, get_origin, assert_type
from finch._types import NoneType
-from finch._utils import (
- is_dict,
- is_list,
- is_list_type,
- is_union_type,
-)
+from finch._utils import is_dict, is_list, is_list_type, is_union_type
from finch._compat import PYDANTIC_V2, field_outer_type, get_model_fields
from finch._models import BaseModel
From 61018d4794ec858953dc0a3746054dbc04807ff9 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Thu, 7 Dec 2023 18:24:09 +0000
Subject: [PATCH 17/26] chore(internal): enable more lint rules (#217)
---
pyproject.toml | 31 ++++++++++++++++++++-----------
requirements-dev.lock | 2 +-
src/finch/__init__.py | 2 +-
src/finch/_streaming.py | 4 ++--
src/finch/_types.py | 1 +
src/finch/_utils/_utils.py | 8 +++++---
src/finch/resources/webhooks.py | 16 ++++++++--------
tests/test_utils/test_proxy.py | 2 +-
tests/utils.py | 2 +-
9 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index b831f420..31c3cd8c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -45,17 +45,18 @@ Repository = "https://github.com/Finch-API/finch-api-python"
[tool.rye]
managed = true
+# version pins are in requirements-dev.lock
dev-dependencies = [
- "pyright==1.1.332",
- "mypy==1.7.1",
- "black==23.3.0",
- "respx==0.20.2",
- "pytest==7.1.1",
- "pytest-asyncio==0.21.1",
- "ruff==0.0.282",
- "isort==5.10.1",
- "time-machine==2.9.0",
- "nox==2023.4.22",
+ "pyright",
+ "mypy",
+ "black",
+ "respx",
+ "pytest",
+ "pytest-asyncio",
+ "ruff",
+ "isort",
+ "time-machine",
+ "nox",
"dirty-equals>=0.6.0",
]
@@ -132,9 +133,11 @@ extra_standard_library = ["typing_extensions"]
[tool.ruff]
line-length = 120
-format = "grouped"
+output-format = "grouped"
target-version = "py37"
select = [
+ # bugbear rules
+ "B",
# remove unused imports
"F401",
# bare except statements
@@ -145,6 +148,12 @@ select = [
"T201",
"T203",
]
+ignore = [
+ # lru_cache in methods, will be fixed separately
+ "B019",
+ # mutable defaults
+ "B006",
+]
unfixable = [
# disable auto fix for print statements
"T201",
diff --git a/requirements-dev.lock b/requirements-dev.lock
index ce154682..2ad33ff6 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -43,7 +43,7 @@ pytest-asyncio==0.21.1
python-dateutil==2.8.2
pytz==2023.3.post1
respx==0.20.2
-ruff==0.0.282
+ruff==0.1.7
six==1.16.0
sniffio==1.3.0
time-machine==2.9.0
diff --git a/src/finch/__init__.py b/src/finch/__init__.py
index c720161f..37904fae 100644
--- a/src/finch/__init__.py
+++ b/src/finch/__init__.py
@@ -75,7 +75,7 @@
for __name in __all__:
if not __name.startswith("__"):
try:
- setattr(__locals[__name], "__module__", "finch")
+ __locals[__name].__module__ = "finch"
except (TypeError, AttributeError):
# Some of our exported symbols are builtins which we can't set attributes for.
pass
diff --git a/src/finch/_streaming.py b/src/finch/_streaming.py
index 913159fd..e816ca74 100644
--- a/src/finch/_streaming.py
+++ b/src/finch/_streaming.py
@@ -51,7 +51,7 @@ def __stream__(self) -> Iterator[ResponseT]:
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
# Ensure the entire stream is consumed
- for sse in iterator:
+ for _sse in iterator:
...
@@ -94,7 +94,7 @@ async def __stream__(self) -> AsyncIterator[ResponseT]:
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
# Ensure the entire stream is consumed
- async for sse in iterator:
+ async for _sse in iterator:
...
diff --git a/src/finch/_types.py b/src/finch/_types.py
index e12f064d..c4f652b4 100644
--- a/src/finch/_types.py
+++ b/src/finch/_types.py
@@ -44,6 +44,7 @@
class BinaryResponseContent(ABC):
+ @abstractmethod
def __init__(
self,
response: Any,
diff --git a/src/finch/_utils/_utils.py b/src/finch/_utils/_utils.py
index 83f88cc3..c874d368 100644
--- a/src/finch/_utils/_utils.py
+++ b/src/finch/_utils/_utils.py
@@ -194,8 +194,8 @@ def extract_type_arg(typ: type, index: int) -> type:
args = get_args(typ)
try:
return cast(type, args[index])
- except IndexError:
- raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not")
+ except IndexError as err:
+ raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err
def deepcopy_minimal(item: _T) -> _T:
@@ -275,7 +275,9 @@ def wrapper(*args: object, **kwargs: object) -> object:
try:
given_params.add(positional[i])
except IndexError:
- raise TypeError(f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given")
+ raise TypeError(
+ f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given"
+ ) from None
for key in kwargs.keys():
given_params.add(key)
diff --git a/src/finch/resources/webhooks.py b/src/finch/resources/webhooks.py
index 13b88d61..40c7678b 100644
--- a/src/finch/resources/webhooks.py
+++ b/src/finch/resources/webhooks.py
@@ -56,8 +56,8 @@ def verify_signature(
try:
parsedSecret = base64.b64decode(secret)
- except Exception:
- raise ValueError("Bad 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")
@@ -68,8 +68,8 @@ def verify_signature(
try:
timestamp = datetime.fromtimestamp(float(msg_timestamp), tz=timezone.utc)
- except Exception:
- raise ValueError("Invalid timestamp header: " + msg_timestamp + ". Could not convert to timestamp")
+ 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):
@@ -152,8 +152,8 @@ def verify_signature(
try:
parsedSecret = base64.b64decode(secret)
- except Exception:
- raise ValueError("Bad 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")
@@ -164,8 +164,8 @@ def verify_signature(
try:
timestamp = datetime.fromtimestamp(float(msg_timestamp), tz=timezone.utc)
- except Exception:
- raise ValueError("Invalid timestamp header: " + msg_timestamp + ". Could not convert to timestamp")
+ 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):
diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py
index 4a7336a8..f5a7028d 100644
--- a/tests/test_utils/test_proxy.py
+++ b/tests/test_utils/test_proxy.py
@@ -19,5 +19,5 @@ def test_recursive_proxy() -> None:
assert repr(proxy) == "RecursiveLazyProxy"
assert str(proxy) == "RecursiveLazyProxy"
assert dir(proxy) == []
- assert getattr(type(proxy), "__name__") == "RecursiveLazyProxy"
+ assert type(proxy).__name__ == "RecursiveLazyProxy"
assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy"
diff --git a/tests/utils.py b/tests/utils.py
index bc62203d..3cd9cf08 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -91,7 +91,7 @@ def assert_matches_type(
traceback.print_exc()
continue
- assert False, "Did not match any variants"
+ raise AssertionError("Did not match any variants")
elif issubclass(origin, BaseModel):
assert isinstance(value, type_)
assert assert_matches_model(type_, cast(Any, value), path=path)
From d0f1493c4bbbabe9fa9b7c5c3ef55588820ba87b Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Thu, 7 Dec 2023 19:20:16 +0000
Subject: [PATCH 18/26] feat(api): add `lp` tax payer type enum value (#218)
---
src/finch/types/hris/company.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/finch/types/hris/company.py b/src/finch/types/hris/company.py
index fb0ea41f..6823a150 100644
--- a/src/finch/types/hris/company.py
+++ b/src/finch/types/hris/company.py
@@ -46,7 +46,9 @@ class Entity(BaseModel):
subtype: Optional[Literal["s_corporation", "c_corporation", "b_corporation"]] = None
"""The tax payer subtype of the company."""
- type: Optional[Literal["llc", "corporation", "sole_proprietor", "non_profit", "partnership", "cooperative"]] = None
+ type: Optional[
+ Literal["llc", "lp", "corporation", "sole_proprietor", "non_profit", "partnership", "cooperative"]
+ ] = None
"""The tax payer type of the company."""
From ee8fb3977610c5a7578353042553665a07943b42 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Fri, 8 Dec 2023 10:07:19 +0000
Subject: [PATCH 19/26] fix(errors): properly assign APIError.body (#219)
---
src/finch/_exceptions.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/finch/_exceptions.py b/src/finch/_exceptions.py
index 8d69569f..ba7b00fa 100644
--- a/src/finch/_exceptions.py
+++ b/src/finch/_exceptions.py
@@ -41,6 +41,7 @@ def __init__(self, message: str, request: httpx.Request, *, body: object | None)
super().__init__(message)
self.request = request
self.message = message
+ self.body = body
class APIResponseValidationError(APIError):
From c6347717feebc43eb69d191aeee3369aa010e0a0 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Fri, 8 Dec 2023 19:02:10 +0000
Subject: [PATCH 20/26] fix: avoid leaking memory when Client.with_options is
used (#220)
Fixes https://github.com/openai/openai-python/issues/865.
---
pyproject.toml | 2 -
src/finch/_base_client.py | 28 +++++----
src/finch/_client.py | 4 +-
tests/test_client.py | 124 ++++++++++++++++++++++++++++++++++++++
4 files changed, 141 insertions(+), 17 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 31c3cd8c..6d403b5a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -149,8 +149,6 @@ select = [
"T203",
]
ignore = [
- # lru_cache in methods, will be fixed separately
- "B019",
# mutable defaults
"B006",
]
diff --git a/src/finch/_base_client.py b/src/finch/_base_client.py
index 2e5678e8..bbbb8a54 100644
--- a/src/finch/_base_client.py
+++ b/src/finch/_base_client.py
@@ -403,14 +403,12 @@ def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers:
headers_dict = _merge_mappings(self.default_headers, custom_headers)
self._validate_headers(headers_dict, custom_headers)
+ # headers are case-insensitive while dictionaries are not.
headers = httpx.Headers(headers_dict)
idempotency_header = self._idempotency_header
if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers:
- if not options.idempotency_key:
- options.idempotency_key = self._idempotency_key()
-
- headers[idempotency_header] = options.idempotency_key
+ headers[idempotency_header] = options.idempotency_key or self._idempotency_key()
return headers
@@ -594,16 +592,8 @@ def base_url(self) -> URL:
def base_url(self, url: URL | str) -> None:
self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url))
- @lru_cache(maxsize=None)
def platform_headers(self) -> Dict[str, str]:
- return {
- "X-Stainless-Lang": "python",
- "X-Stainless-Package-Version": self._version,
- "X-Stainless-OS": str(get_platform()),
- "X-Stainless-Arch": str(get_architecture()),
- "X-Stainless-Runtime": platform.python_implementation(),
- "X-Stainless-Runtime-Version": platform.python_version(),
- }
+ return platform_headers(self._version)
def _calculate_retry_timeout(
self,
@@ -1691,6 +1681,18 @@ def get_platform() -> Platform:
return "Unknown"
+@lru_cache(maxsize=None)
+def platform_headers(version: str) -> Dict[str, str]:
+ return {
+ "X-Stainless-Lang": "python",
+ "X-Stainless-Package-Version": version,
+ "X-Stainless-OS": str(get_platform()),
+ "X-Stainless-Arch": str(get_architecture()),
+ "X-Stainless-Runtime": platform.python_implementation(),
+ "X-Stainless-Runtime-Version": platform.python_version(),
+ }
+
+
class OtherArch:
def __init__(self, name: str) -> None:
self.name = name
diff --git a/src/finch/_client.py b/src/finch/_client.py
index 149406a0..76629545 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -236,7 +236,7 @@ def copy(
client_id=client_id or self.client_id,
client_secret=client_secret or self.client_secret,
webhook_secret=webhook_secret or self.webhook_secret,
- base_url=base_url or str(self.base_url),
+ base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
http_client=http_client,
connection_pool_limits=connection_pool_limits,
@@ -542,7 +542,7 @@ def copy(
client_id=client_id or self.client_id,
client_secret=client_secret or self.client_secret,
webhook_secret=webhook_secret or self.webhook_secret,
- base_url=base_url or str(self.base_url),
+ base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
http_client=http_client,
connection_pool_limits=connection_pool_limits,
diff --git a/tests/test_client.py b/tests/test_client.py
index a37278e9..d5010a92 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -2,10 +2,12 @@
from __future__ import annotations
+import gc
import os
import json
import asyncio
import inspect
+import tracemalloc
from typing import Any, Union, cast
from unittest import mock
@@ -174,6 +176,67 @@ def test_copy_signature(self) -> None:
copy_param = copy_signature.parameters.get(name)
assert copy_param is not None, f"copy() signature is missing the {name} param"
+ def test_copy_build_request(self) -> None:
+ options = FinalRequestOptions(method="get", url="/foo")
+
+ def build_request(options: FinalRequestOptions) -> None:
+ client = self.client.copy()
+ client._build_request(options)
+
+ # ensure that the machinery is warmed up before tracing starts.
+ build_request(options)
+ gc.collect()
+
+ tracemalloc.start(1000)
+
+ snapshot_before = tracemalloc.take_snapshot()
+
+ ITERATIONS = 10
+ for _ in range(ITERATIONS):
+ build_request(options)
+ gc.collect()
+
+ snapshot_after = tracemalloc.take_snapshot()
+
+ tracemalloc.stop()
+
+ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.StatisticDiff) -> None:
+ if diff.count == 0:
+ # Avoid false positives by considering only leaks (i.e. allocations that persist).
+ return
+
+ if diff.count % ITERATIONS != 0:
+ # Avoid false positives by considering only leaks that appear per iteration.
+ return
+
+ for frame in diff.traceback:
+ if any(
+ frame.filename.endswith(fragment)
+ for fragment in [
+ # to_raw_response_wrapper leaks through the @functools.wraps() decorator.
+ #
+ # removing the decorator fixes the leak for reasons we don't understand.
+ "finch/_response.py",
+ # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason.
+ "finch/_compat.py",
+ # Standard library leaks we don't care about.
+ "/logging/__init__.py",
+ ]
+ ):
+ return
+
+ leaks.append(diff)
+
+ leaks: list[tracemalloc.StatisticDiff] = []
+ for diff in snapshot_after.compare_to(snapshot_before, "traceback"):
+ add_leak(leaks, diff)
+ if leaks:
+ for leak in leaks:
+ print("MEMORY LEAK:", leak)
+ for frame in leak.traceback:
+ print(frame)
+ raise AssertionError()
+
def test_request_timeout(self) -> None:
request = self.client._build_request(FinalRequestOptions(method="get", url="/foo"))
timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
@@ -882,6 +945,67 @@ def test_copy_signature(self) -> None:
copy_param = copy_signature.parameters.get(name)
assert copy_param is not None, f"copy() signature is missing the {name} param"
+ def test_copy_build_request(self) -> None:
+ options = FinalRequestOptions(method="get", url="/foo")
+
+ def build_request(options: FinalRequestOptions) -> None:
+ client = self.client.copy()
+ client._build_request(options)
+
+ # ensure that the machinery is warmed up before tracing starts.
+ build_request(options)
+ gc.collect()
+
+ tracemalloc.start(1000)
+
+ snapshot_before = tracemalloc.take_snapshot()
+
+ ITERATIONS = 10
+ for _ in range(ITERATIONS):
+ build_request(options)
+ gc.collect()
+
+ snapshot_after = tracemalloc.take_snapshot()
+
+ tracemalloc.stop()
+
+ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.StatisticDiff) -> None:
+ if diff.count == 0:
+ # Avoid false positives by considering only leaks (i.e. allocations that persist).
+ return
+
+ if diff.count % ITERATIONS != 0:
+ # Avoid false positives by considering only leaks that appear per iteration.
+ return
+
+ for frame in diff.traceback:
+ if any(
+ frame.filename.endswith(fragment)
+ for fragment in [
+ # to_raw_response_wrapper leaks through the @functools.wraps() decorator.
+ #
+ # removing the decorator fixes the leak for reasons we don't understand.
+ "finch/_response.py",
+ # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason.
+ "finch/_compat.py",
+ # Standard library leaks we don't care about.
+ "/logging/__init__.py",
+ ]
+ ):
+ return
+
+ leaks.append(diff)
+
+ leaks: list[tracemalloc.StatisticDiff] = []
+ for diff in snapshot_after.compare_to(snapshot_before, "traceback"):
+ add_leak(leaks, diff)
+ if leaks:
+ for leak in leaks:
+ print("MEMORY LEAK:", leak)
+ for frame in leak.traceback:
+ print(frame)
+ raise AssertionError()
+
async def test_request_timeout(self) -> None:
request = self.client._build_request(FinalRequestOptions(method="get", url="/foo"))
timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore
From 1c946dd97fc43bfdda3346311282086af8cac6cb Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Mon, 11 Dec 2023 23:54:53 +0000
Subject: [PATCH 21/26] docs: improve README timeout comment (#221)
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e2b76e88..89067751 100644
--- a/README.md
+++ b/README.md
@@ -236,7 +236,7 @@ from finch import Finch
# Configure the default for all requests:
client = Finch(
- # default is 60s
+ # 20 seconds (default is 1 minute)
timeout=20.0,
)
From 7f116d2665c22e08988fb01cbbb692c8c0b79fea Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Tue, 12 Dec 2023 14:56:08 +0000
Subject: [PATCH 22/26] refactor(client): simplify cleanup (#222)
This removes Client.__del__, but users are not expected to call this directly.
---
pyproject.toml | 2 +-
src/finch/_base_client.py | 26 ++++++++++++++++++++------
src/finch/_client.py | 30 ++++--------------------------
tests/test_client.py | 23 ++---------------------
4 files changed, 27 insertions(+), 54 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 6d403b5a..2edff854 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -81,7 +81,7 @@ typecheck = { chain = [
]}
"typecheck:pyright" = "pyright"
"typecheck:verify-types" = "pyright --verifytypes finch --ignoreexternal"
-"typecheck:mypy" = "mypy --enable-incomplete-feature=Unpack ."
+"typecheck:mypy" = "mypy ."
[build-system]
requires = ["hatchling"]
diff --git a/src/finch/_base_client.py b/src/finch/_base_client.py
index bbbb8a54..04a20bfd 100644
--- a/src/finch/_base_client.py
+++ b/src/finch/_base_client.py
@@ -5,6 +5,7 @@
import time
import uuid
import email
+import asyncio
import inspect
import logging
import platform
@@ -672,9 +673,16 @@ def _idempotency_key(self) -> str:
return f"stainless-python-retry-{uuid.uuid4()}"
+class SyncHttpxClientWrapper(httpx.Client):
+ def __del__(self) -> None:
+ try:
+ self.close()
+ except Exception:
+ pass
+
+
class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
_client: httpx.Client
- _has_custom_http_client: bool
_default_stream_cls: type[Stream[Any]] | None = None
def __init__(
@@ -747,7 +755,7 @@ def __init__(
custom_headers=custom_headers,
_strict_response_validation=_strict_response_validation,
)
- self._client = http_client or httpx.Client(
+ self._client = http_client or SyncHttpxClientWrapper(
base_url=base_url,
# cast to a valid type because mypy doesn't understand our type narrowing
timeout=cast(Timeout, timeout),
@@ -755,7 +763,6 @@ def __init__(
transport=transport,
limits=limits,
)
- self._has_custom_http_client = bool(http_client)
def is_closed(self) -> bool:
return self._client.is_closed
@@ -1135,9 +1142,17 @@ def get_api_list(
return self._request_api_list(model, page, opts)
+class AsyncHttpxClientWrapper(httpx.AsyncClient):
+ def __del__(self) -> None:
+ try:
+ # TODO(someday): support non asyncio runtimes here
+ asyncio.get_running_loop().create_task(self.aclose())
+ except Exception:
+ pass
+
+
class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
_client: httpx.AsyncClient
- _has_custom_http_client: bool
_default_stream_cls: type[AsyncStream[Any]] | None = None
def __init__(
@@ -1210,7 +1225,7 @@ def __init__(
custom_headers=custom_headers,
_strict_response_validation=_strict_response_validation,
)
- self._client = http_client or httpx.AsyncClient(
+ self._client = http_client or AsyncHttpxClientWrapper(
base_url=base_url,
# cast to a valid type because mypy doesn't understand our type narrowing
timeout=cast(Timeout, timeout),
@@ -1218,7 +1233,6 @@ def __init__(
transport=transport,
limits=limits,
)
- self._has_custom_http_client = bool(http_client)
def is_closed(self) -> bool:
return self._client.is_closed
diff --git a/src/finch/_client.py b/src/finch/_client.py
index 76629545..404f7fa4 100644
--- a/src/finch/_client.py
+++ b/src/finch/_client.py
@@ -3,7 +3,6 @@
from __future__ import annotations
import os
-import asyncio
from typing import Any, Union, Mapping
from typing_extensions import Self, override
@@ -32,6 +31,8 @@
DEFAULT_MAX_RETRIES,
SyncAPIClient,
AsyncAPIClient,
+ SyncHttpxClientWrapper,
+ AsyncHttpxClientWrapper,
)
__all__ = [
@@ -217,7 +218,7 @@ def copy(
if http_client is not None:
raise ValueError("The 'http_client' argument is mutually exclusive with 'connection_pool_limits'")
- if self._has_custom_http_client:
+ if not isinstance(self._client, SyncHttpxClientWrapper):
raise ValueError(
"A custom HTTP client has been set and is mutually exclusive with the 'connection_pool_limits' argument"
)
@@ -250,16 +251,6 @@ def copy(
# client.with_options(timeout=10).foo.create(...)
with_options = copy
- def __del__(self) -> None:
- if not hasattr(self, "_has_custom_http_client") or not hasattr(self, "close"):
- # this can happen if the '__init__' method raised an error
- return
-
- if self._has_custom_http_client:
- return
-
- self.close()
-
def get_access_token(
self,
code: str,
@@ -523,7 +514,7 @@ def copy(
if http_client is not None:
raise ValueError("The 'http_client' argument is mutually exclusive with 'connection_pool_limits'")
- if self._has_custom_http_client:
+ if not isinstance(self._client, AsyncHttpxClientWrapper):
raise ValueError(
"A custom HTTP client has been set and is mutually exclusive with the 'connection_pool_limits' argument"
)
@@ -556,19 +547,6 @@ def copy(
# client.with_options(timeout=10).foo.create(...)
with_options = copy
- def __del__(self) -> None:
- if not hasattr(self, "_has_custom_http_client") or not hasattr(self, "close"):
- # this can happen if the '__init__' method raised an error
- return
-
- if self._has_custom_http_client:
- return
-
- try:
- asyncio.get_running_loop().create_task(self.close())
- except Exception:
- pass
-
async def get_access_token(
self,
code: str,
diff --git a/tests/test_client.py b/tests/test_client.py
index d5010a92..d369741d 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -695,14 +695,6 @@ def test_proxies_option_mutually_exclusive_with_http_client(self) -> None:
http_client=http_client,
)
- def test_client_del(self) -> None:
- client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
- assert not client.is_closed()
-
- client.__del__()
-
- assert client.is_closed()
-
def test_copied_client_does_not_close_http(self) -> None:
client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
assert not client.is_closed()
@@ -710,9 +702,8 @@ def test_copied_client_does_not_close_http(self) -> None:
copied = client.copy()
assert copied is not client
- copied.__del__()
+ del copied
- assert not copied.is_closed()
assert not client.is_closed()
def test_client_context_manager(self) -> None:
@@ -1464,15 +1455,6 @@ async def test_proxies_option_mutually_exclusive_with_http_client(self) -> None:
http_client=http_client,
)
- async def test_client_del(self) -> None:
- client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
- assert not client.is_closed()
-
- client.__del__()
-
- await asyncio.sleep(0.2)
- assert client.is_closed()
-
async def test_copied_client_does_not_close_http(self) -> None:
client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
assert not client.is_closed()
@@ -1480,10 +1462,9 @@ async def test_copied_client_does_not_close_http(self) -> None:
copied = client.copy()
assert copied is not client
- copied.__del__()
+ del copied
await asyncio.sleep(0.2)
- assert not copied.is_closed()
assert not client.is_closed()
async def test_client_context_manager(self) -> None:
From 481dc7de11733b2493e820ff241b7999d873fd16 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Tue, 12 Dec 2023 18:16:27 -0500
Subject: [PATCH 23/26] refactor: simplify internal error handling (#223)
---
src/finch/_base_client.py | 102 +++++++++++++++++---------------------
tests/test_client.py | 53 +-------------------
2 files changed, 47 insertions(+), 108 deletions(-)
diff --git a/src/finch/_base_client.py b/src/finch/_base_client.py
index 04a20bfd..92189617 100644
--- a/src/finch/_base_client.py
+++ b/src/finch/_base_client.py
@@ -873,40 +873,25 @@ def _request(
request = self._build_request(options)
self._prepare_request(request)
- response = None
-
try:
response = self._client.send(
request,
auth=self.custom_auth,
stream=stream or self._should_stream_response_body(request=request),
)
- log.debug(
- 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
- )
- response.raise_for_status()
- except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
- if retries > 0 and self._should_retry(err.response):
- err.response.close()
+ except httpx.TimeoutException as err:
+ if retries > 0:
return self._retry_request(
options,
cast_to,
retries,
- err.response.headers,
stream=stream,
stream_cls=stream_cls,
+ response_headers=None,
)
- # If the response is streamed then we need to explicitly read the response
- # to completion before attempting to access the response text.
- if not err.response.is_closed:
- err.response.read()
-
- raise self._make_status_error_from_response(err.response) from None
- except httpx.TimeoutException as err:
- if response is not None:
- response.close()
-
+ raise APITimeoutError(request=request) from err
+ except Exception as err:
if retries > 0:
return self._retry_request(
options,
@@ -914,25 +899,35 @@ def _request(
retries,
stream=stream,
stream_cls=stream_cls,
- response_headers=response.headers if response is not None else None,
+ response_headers=None,
)
- raise APITimeoutError(request=request) from err
- except Exception as err:
- if response is not None:
- response.close()
+ raise APIConnectionError(request=request) from err
- if retries > 0:
+ log.debug(
+ 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
+ )
+
+ try:
+ response.raise_for_status()
+ except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
+ if retries > 0 and self._should_retry(err.response):
+ err.response.close()
return self._retry_request(
options,
cast_to,
retries,
+ err.response.headers,
stream=stream,
stream_cls=stream_cls,
- response_headers=response.headers if response is not None else None,
)
- raise APIConnectionError(request=request) from err
+ # If the response is streamed then we need to explicitly read the response
+ # to completion before attempting to access the response text.
+ if not err.response.is_closed:
+ err.response.read()
+
+ raise self._make_status_error_from_response(err.response) from None
return self._process_response(
cast_to=cast_to,
@@ -1340,40 +1335,25 @@ async def _request(
request = self._build_request(options)
await self._prepare_request(request)
- response = None
-
try:
response = await self._client.send(
request,
auth=self.custom_auth,
stream=stream or self._should_stream_response_body(request=request),
)
- log.debug(
- 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
- )
- response.raise_for_status()
- except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
- if retries > 0 and self._should_retry(err.response):
- await err.response.aclose()
+ except httpx.TimeoutException as err:
+ if retries > 0:
return await self._retry_request(
options,
cast_to,
retries,
- err.response.headers,
stream=stream,
stream_cls=stream_cls,
+ response_headers=None,
)
- # If the response is streamed then we need to explicitly read the response
- # to completion before attempting to access the response text.
- if not err.response.is_closed:
- await err.response.aread()
-
- raise self._make_status_error_from_response(err.response) from None
- except httpx.TimeoutException as err:
- if response is not None:
- await response.aclose()
-
+ raise APITimeoutError(request=request) from err
+ except Exception as err:
if retries > 0:
return await self._retry_request(
options,
@@ -1381,25 +1361,35 @@ async def _request(
retries,
stream=stream,
stream_cls=stream_cls,
- response_headers=response.headers if response is not None else None,
+ response_headers=None,
)
- raise APITimeoutError(request=request) from err
- except Exception as err:
- if response is not None:
- await response.aclose()
+ raise APIConnectionError(request=request) from err
- if retries > 0:
+ log.debug(
+ 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
+ )
+
+ try:
+ response.raise_for_status()
+ except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
+ if retries > 0 and self._should_retry(err.response):
+ await err.response.aclose()
return await self._retry_request(
options,
cast_to,
retries,
+ err.response.headers,
stream=stream,
stream_cls=stream_cls,
- response_headers=response.headers if response is not None else None,
)
- raise APIConnectionError(request=request) from err
+ # If the response is streamed then we need to explicitly read the response
+ # to completion before attempting to access the response text.
+ if not err.response.is_closed:
+ await err.response.aread()
+
+ raise self._make_status_error_from_response(err.response) from None
return self._process_response(
cast_to=cast_to,
diff --git a/tests/test_client.py b/tests/test_client.py
index d369741d..b2d64aee 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -20,7 +20,7 @@
from finch._types import Omit
from finch._client import Finch, AsyncFinch
from finch._models import BaseModel, FinalRequestOptions
-from finch._exceptions import APIStatusError, APIResponseValidationError
+from finch._exceptions import APIResponseValidationError
from finch._base_client import (
DEFAULT_TIMEOUT,
HTTPX_DEFAULT_TIMEOUT,
@@ -772,31 +772,6 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str
calculated = client._calculate_retry_timeout(remaining_retries, options, headers)
assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType]
- @pytest.mark.respx(base_url=base_url)
- def test_status_error_within_httpx(self, respx_mock: MockRouter) -> None:
- respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
-
- def on_response(response: httpx.Response) -> None:
- raise httpx.HTTPStatusError(
- "Simulating an error inside httpx",
- response=response,
- request=response.request,
- )
-
- client = Finch(
- base_url=base_url,
- access_token=access_token,
- _strict_response_validation=True,
- http_client=httpx.Client(
- event_hooks={
- "response": [on_response],
- }
- ),
- max_retries=0,
- )
- with pytest.raises(APIStatusError):
- client.post("/foo", cast_to=httpx.Response)
-
class TestAsyncFinch:
client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
@@ -1535,29 +1510,3 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte
options = FinalRequestOptions(method="get", url="/foo", max_retries=3)
calculated = client._calculate_retry_timeout(remaining_retries, options, headers)
assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType]
-
- @pytest.mark.respx(base_url=base_url)
- @pytest.mark.asyncio
- async def test_status_error_within_httpx(self, respx_mock: MockRouter) -> None:
- respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"}))
-
- def on_response(response: httpx.Response) -> None:
- raise httpx.HTTPStatusError(
- "Simulating an error inside httpx",
- response=response,
- request=response.request,
- )
-
- client = AsyncFinch(
- base_url=base_url,
- access_token=access_token,
- _strict_response_validation=True,
- http_client=httpx.AsyncClient(
- event_hooks={
- "response": [on_response],
- }
- ),
- max_retries=0,
- )
- with pytest.raises(APIStatusError):
- await client.post("/foo", cast_to=httpx.Response)
From f0b3fb7fceb4cdfe42abc5e49e04de30633cc55c Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Tue, 12 Dec 2023 20:27:22 -0500
Subject: [PATCH 24/26] refactor: remove unused model types used in params
(#224)
---
src/finch/types/shared_params/__init__.py | 5 --
.../types/shared_params/operation_support.py | 9 ---
.../shared_params/operation_support_matrix.py | 56 -------------------
src/finch/types/shared_params/paging.py | 15 -----
4 files changed, 85 deletions(-)
delete mode 100644 src/finch/types/shared_params/__init__.py
delete mode 100644 src/finch/types/shared_params/operation_support.py
delete mode 100644 src/finch/types/shared_params/operation_support_matrix.py
delete mode 100644 src/finch/types/shared_params/paging.py
diff --git a/src/finch/types/shared_params/__init__.py b/src/finch/types/shared_params/__init__.py
deleted file mode 100644
index 6c699bd7..00000000
--- a/src/finch/types/shared_params/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# File generated from our OpenAPI spec by Stainless.
-
-from .paging import Paging as Paging
-from .operation_support import OperationSupport as OperationSupport
-from .operation_support_matrix import OperationSupportMatrix as OperationSupportMatrix
diff --git a/src/finch/types/shared_params/operation_support.py b/src/finch/types/shared_params/operation_support.py
deleted file mode 100644
index 290a5214..00000000
--- a/src/finch/types/shared_params/operation_support.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# File generated from our OpenAPI spec by Stainless.
-
-from __future__ import annotations
-
-from typing_extensions import Literal
-
-__all__ = ["OperationSupport"]
-
-OperationSupport = Literal["supported", "not_supported_by_finch", "not_supported_by_provider", "client_access_only"]
diff --git a/src/finch/types/shared_params/operation_support_matrix.py b/src/finch/types/shared_params/operation_support_matrix.py
deleted file mode 100644
index 4fa6df6b..00000000
--- a/src/finch/types/shared_params/operation_support_matrix.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# File generated from our OpenAPI spec by Stainless.
-
-from __future__ import annotations
-
-from typing_extensions import TypedDict
-
-from ..shared import OperationSupport
-from .operation_support import OperationSupport
-
-__all__ = ["OperationSupportMatrix"]
-
-
-class OperationSupportMatrix(TypedDict, total=False):
- create: OperationSupport
- """
- - `supported`: This operation is supported by both the provider and Finch
- - `not_supported_by_finch`: This operation is not supported by Finch but
- supported by the provider
- - `not_supported_by_provider`: This operation is not supported by the provider,
- so Finch cannot support
- - `client_access_only`: This behavior is supported by the provider, but only
- available to the client and not to Finch
- """
-
- delete: OperationSupport
- """
- - `supported`: This operation is supported by both the provider and Finch
- - `not_supported_by_finch`: This operation is not supported by Finch but
- supported by the provider
- - `not_supported_by_provider`: This operation is not supported by the provider,
- so Finch cannot support
- - `client_access_only`: This behavior is supported by the provider, but only
- available to the client and not to Finch
- """
-
- read: OperationSupport
- """
- - `supported`: This operation is supported by both the provider and Finch
- - `not_supported_by_finch`: This operation is not supported by Finch but
- supported by the provider
- - `not_supported_by_provider`: This operation is not supported by the provider,
- so Finch cannot support
- - `client_access_only`: This behavior is supported by the provider, but only
- available to the client and not to Finch
- """
-
- update: OperationSupport
- """
- - `supported`: This operation is supported by both the provider and Finch
- - `not_supported_by_finch`: This operation is not supported by Finch but
- supported by the provider
- - `not_supported_by_provider`: This operation is not supported by the provider,
- so Finch cannot support
- - `client_access_only`: This behavior is supported by the provider, but only
- available to the client and not to Finch
- """
diff --git a/src/finch/types/shared_params/paging.py b/src/finch/types/shared_params/paging.py
deleted file mode 100644
index e3ea2ca9..00000000
--- a/src/finch/types/shared_params/paging.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless.
-
-from __future__ import annotations
-
-from typing_extensions import TypedDict
-
-__all__ = ["Paging"]
-
-
-class Paging(TypedDict, total=False):
- count: int
- """The total number of elements for the entire query (not just the given page)"""
-
- offset: int
- """The current start index of the returned list of elements"""
From 7147466ca5ce520e88fb392bd2d84be99a03e2b7 Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Sat, 16 Dec 2023 19:38:10 -0500
Subject: [PATCH 25/26] chore(ci): run release workflow once per day (#226)
---
.github/workflows/create-releases.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml
index 4d08483e..1f1c959f 100644
--- a/.github/workflows/create-releases.yml
+++ b/.github/workflows/create-releases.yml
@@ -1,5 +1,7 @@
name: Create releases
on:
+ schedule:
+ - cron: '0 5 * * *' # every day at 5am UTC
push:
branches:
- main
From 2fe598125e84903f6e4094bddead231a25241e8d Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Sat, 16 Dec 2023 19:38:31 -0500
Subject: [PATCH 26/26] release: 0.9.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 46 +++++++++++++++++++++++++++++++++++
pyproject.toml | 2 +-
src/finch/_version.py | 2 +-
4 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 34dc535b..6d78745c 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.8.2"
+ ".": "0.9.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9038084..e5825e3a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,51 @@
# Changelog
+## 0.9.0 (2023-12-17)
+
+Full Changelog: [v0.8.2...v0.9.0](https://github.com/Finch-API/finch-api-python/compare/v0.8.2...v0.9.0)
+
+### Features
+
+* **api:** add `/jobs` endpoints ([#210](https://github.com/Finch-API/finch-api-python/issues/210)) ([cd3cc6f](https://github.com/Finch-API/finch-api-python/commit/cd3cc6febbb46537d6694303c52fbfa266e762cd))
+* **api:** add `client_type` and `connection_type` to introspection ([#211](https://github.com/Finch-API/finch-api-python/issues/211)) ([d354f0a](https://github.com/Finch-API/finch-api-python/commit/d354f0a501deeea8090c0e2a6200302fe40a7638))
+* **api:** add `lp` tax payer type enum value ([#218](https://github.com/Finch-API/finch-api-python/issues/218)) ([d0f1493](https://github.com/Finch-API/finch-api-python/commit/d0f1493c4bbbabe9fa9b7c5c3ef55588820ba87b))
+* **pagination:** remove unused types ([#215](https://github.com/Finch-API/finch-api-python/issues/215)) ([9adf490](https://github.com/Finch-API/finch-api-python/commit/9adf490d6b23ddb642eb630be867690a8f8a8693))
+
+
+### Bug Fixes
+
+* avoid leaking memory when Client.with_options is used ([#220](https://github.com/Finch-API/finch-api-python/issues/220)) ([c634771](https://github.com/Finch-API/finch-api-python/commit/c6347717feebc43eb69d191aeee3369aa010e0a0))
+* **client:** correct base_url setter implementation ([#207](https://github.com/Finch-API/finch-api-python/issues/207)) ([5e04fa7](https://github.com/Finch-API/finch-api-python/commit/5e04fa773d4603d0be73aa67268b17fdc4f6fed2))
+* **client:** ensure retried requests are closed ([#204](https://github.com/Finch-API/finch-api-python/issues/204)) ([0659932](https://github.com/Finch-API/finch-api-python/commit/0659932aaaa69850982e6acbe076a4af7980efcd))
+* **errors:** properly assign APIError.body ([#219](https://github.com/Finch-API/finch-api-python/issues/219)) ([ee8fb39](https://github.com/Finch-API/finch-api-python/commit/ee8fb3977610c5a7578353042553665a07943b42))
+
+
+### Chores
+
+* **ci:** run release workflow once per day ([#226](https://github.com/Finch-API/finch-api-python/issues/226)) ([7147466](https://github.com/Finch-API/finch-api-python/commit/7147466ca5ce520e88fb392bd2d84be99a03e2b7))
+* **internal:** add tests for proxy change ([#203](https://github.com/Finch-API/finch-api-python/issues/203)) ([b5b9f79](https://github.com/Finch-API/finch-api-python/commit/b5b9f79c19e846e2e8fc3fd1faf905a65a6aa7c4))
+* **internal:** enable more lint rules ([#217](https://github.com/Finch-API/finch-api-python/issues/217)) ([61018d4](https://github.com/Finch-API/finch-api-python/commit/61018d4794ec858953dc0a3746054dbc04807ff9))
+* **internal:** reformat imports ([#213](https://github.com/Finch-API/finch-api-python/issues/213)) ([81a6e2f](https://github.com/Finch-API/finch-api-python/commit/81a6e2f22a5c5fe862c693a0b5b2affda78d88af))
+* **internal:** reformat imports ([#216](https://github.com/Finch-API/finch-api-python/issues/216)) ([14c8df0](https://github.com/Finch-API/finch-api-python/commit/14c8df00568bba59acab45ff6cdef2cb04599b43))
+* **internal:** replace string concatenation with f-strings ([#206](https://github.com/Finch-API/finch-api-python/issues/206)) ([7c920a3](https://github.com/Finch-API/finch-api-python/commit/7c920a33c103fadee08cd784f5d028f2ab19411f))
+* **internal:** update formatting ([#214](https://github.com/Finch-API/finch-api-python/issues/214)) ([cd5253c](https://github.com/Finch-API/finch-api-python/commit/cd5253c9a8417eec88dc8c30fdfa817ec1519a9e))
+* **internal:** update lock file ([#201](https://github.com/Finch-API/finch-api-python/issues/201)) ([42de23d](https://github.com/Finch-API/finch-api-python/commit/42de23d5c7a3b9253396b94af7884e7a9300b841))
+* **internal:** updates to proxy helper ([#202](https://github.com/Finch-API/finch-api-python/issues/202)) ([2049c50](https://github.com/Finch-API/finch-api-python/commit/2049c50e723ec6ec4b4d46a18fa87800a58d581a))
+* **package:** lift anyio v4 restriction ([#208](https://github.com/Finch-API/finch-api-python/issues/208)) ([e1ed4a5](https://github.com/Finch-API/finch-api-python/commit/e1ed4a53591362f5e2579e301b43529b64f2fc8b))
+
+
+### Documentation
+
+* improve README timeout comment ([#221](https://github.com/Finch-API/finch-api-python/issues/221)) ([1c946dd](https://github.com/Finch-API/finch-api-python/commit/1c946dd97fc43bfdda3346311282086af8cac6cb))
+* **readme:** update example snippets ([#205](https://github.com/Finch-API/finch-api-python/issues/205)) ([4ff1a6b](https://github.com/Finch-API/finch-api-python/commit/4ff1a6b04ba8e3301ac6ff4a612bb8aab801abd0))
+
+
+### Refactors
+
+* **client:** simplify cleanup ([#222](https://github.com/Finch-API/finch-api-python/issues/222)) ([7f116d2](https://github.com/Finch-API/finch-api-python/commit/7f116d2665c22e08988fb01cbbb692c8c0b79fea))
+* remove unused model types used in params ([#224](https://github.com/Finch-API/finch-api-python/issues/224)) ([f0b3fb7](https://github.com/Finch-API/finch-api-python/commit/f0b3fb7fceb4cdfe42abc5e49e04de30633cc55c))
+* simplify internal error handling ([#223](https://github.com/Finch-API/finch-api-python/issues/223)) ([481dc7d](https://github.com/Finch-API/finch-api-python/commit/481dc7de11733b2493e820ff241b7999d873fd16))
+
## 0.8.2 (2023-11-28)
Full Changelog: [v0.8.1...v0.8.2](https://github.com/Finch-API/finch-api-python/compare/v0.8.1...v0.8.2)
diff --git a/pyproject.toml b/pyproject.toml
index 2edff854..b477e34b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "finch-api"
-version = "0.8.2"
+version = "0.9.0"
description = "The official Python library for the Finch API"
readme = "README.md"
license = "Apache-2.0"
diff --git a/src/finch/_version.py b/src/finch/_version.py
index d085a27d..cfd63a12 100644
--- a/src/finch/_version.py
+++ b/src/finch/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless.
__title__ = "finch"
-__version__ = "0.8.2" # x-release-please-version
+__version__ = "0.9.0" # x-release-please-version