Skip to content

Commit fab3cd1

Browse files
stainless-app[bot]stainless-bot
authored andcommitted
feat(api): api update (#511)
1 parent 80c52ec commit fab3cd1

11 files changed

+120
-48
lines changed

.stats.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
configured_endpoints: 39
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-811587ac4ba3634e1b0dd781c54c7a0cb302d612f719036f9c9683166c7197cd.yml
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/finch%2Ffinch-612b573cabcee39c562dc91f5b185e2a0bfdce3a262618f0098602af2199af67.yml

CONTRIBUTING.md

+24-20
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
### With Rye
44

5-
We use [Rye](https://rye.astral.sh/) to manage dependencies so we highly recommend [installing it](https://rye.astral.sh/guide/installation/) as it will automatically provision a Python environment with the expected Python version.
5+
We use [Rye](https://rye.astral.sh/) to manage dependencies because it will automatically provision a Python environment with the expected Python version. To set it up, run:
66

7-
After installing Rye, you'll just have to run this command:
7+
```sh
8+
$ ./scripts/bootstrap
9+
```
10+
11+
Or [install Rye manually](https://rye.astral.sh/guide/installation/) and run:
812

913
```sh
1014
$ rye sync --all-features
@@ -39,17 +43,17 @@ modify the contents of the `src/finch/lib/` and `examples/` directories.
3943

4044
All files in the `examples/` directory are not modified by the generator and can be freely edited or added to.
4145

42-
```bash
46+
```py
4347
# add an example to examples/<your-example>.py
4448

4549
#!/usr/bin/env -S rye run python
4650
4751
```
4852

49-
```
50-
chmod +x examples/<your-example>.py
53+
```sh
54+
$ chmod +x examples/<your-example>.py
5155
# run the example against your api
52-
./examples/<your-example>.py
56+
$ ./examples/<your-example>.py
5357
```
5458

5559
## Using the repository from source
@@ -58,8 +62,8 @@ If you’d like to use the repository from source, you can either install from g
5862

5963
To install via git:
6064

61-
```bash
62-
pip install git+ssh://[email protected]/Finch-API/finch-api-python.git
65+
```sh
66+
$ pip install git+ssh://[email protected]/Finch-API/finch-api-python.git
6367
```
6468

6569
Alternatively, you can build from source and install the wheel file:
@@ -68,29 +72,29 @@ Building this package will create two files in the `dist/` directory, a `.tar.gz
6872

6973
To create a distributable version of the library, all you have to do is run this command:
7074

71-
```bash
72-
rye build
75+
```sh
76+
$ rye build
7377
# or
74-
python -m build
78+
$ python -m build
7579
```
7680

7781
Then to install:
7882

7983
```sh
80-
pip install ./path-to-wheel-file.whl
84+
$ pip install ./path-to-wheel-file.whl
8185
```
8286

8387
## Running tests
8488

8589
Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.
8690

87-
```bash
91+
```sh
8892
# you will need npm installed
89-
npx prism mock path/to/your/openapi.yml
93+
$ npx prism mock path/to/your/openapi.yml
9094
```
9195

92-
```bash
93-
rye run pytest
96+
```sh
97+
$ ./scripts/test
9498
```
9599

96100
## Linting and formatting
@@ -100,14 +104,14 @@ This repository uses [ruff](https://github.com/astral-sh/ruff) and
100104

101105
To lint:
102106

103-
```bash
104-
rye run lint
107+
```sh
108+
$ ./scripts/lint
105109
```
106110

107111
To format and fix all ruff issues automatically:
108112

109-
```bash
110-
rye run format
113+
```sh
114+
$ ./scripts/format
111115
```
112116

113117
## Publishing and releases

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -430,3 +430,7 @@ print(finch.__version__)
430430
## Requirements
431431

432432
Python 3.7 or higher.
433+
434+
## Contributing
435+
436+
See [the contributing documentation](./CONTRIBUTING.md).

src/finch/_base_client.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ def __init__(
144144
self.url = url
145145
self.params = params
146146

147+
@override
148+
def __repr__(self) -> str:
149+
if self.url:
150+
return f"{self.__class__.__name__}(url={self.url})"
151+
return f"{self.__class__.__name__}(params={self.params})"
152+
147153

148154
class BasePage(GenericModel, Generic[_T]):
149155
"""
@@ -690,7 +696,8 @@ def _calculate_retry_timeout(
690696
if retry_after is not None and 0 < retry_after <= 60:
691697
return retry_after
692698

693-
nb_retries = max_retries - remaining_retries
699+
# Also cap retry count to 1000 to avoid any potential overflows with `pow`
700+
nb_retries = min(max_retries - remaining_retries, 1000)
694701

695702
# Apply exponential backoff, but not more than the max.
696703
sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY)

src/finch/_legacy_response.py

+3
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
251251
if cast_to == float:
252252
return cast(R, float(response.text))
253253

254+
if cast_to == bool:
255+
return cast(R, response.text.lower() == "true")
256+
254257
origin = get_origin(cast_to) or cast_to
255258

256259
if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent):

src/finch/_response.py

+3
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
192192
if cast_to == float:
193193
return cast(R, float(response.text))
194194

195+
if cast_to == bool:
196+
return cast(R, response.text.lower() == "true")
197+
195198
origin = get_origin(cast_to) or cast_to
196199

197200
# handle the legacy binary response case

src/finch/types/account_update_event.py

-14
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
"AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEarnings",
4040
"AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployeeDeductions",
4141
"AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerContributions",
42-
"AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions",
4342
"AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsTaxes",
4443
"AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayment",
4544
"AccountUpdateEventDataAuthenticationMethodSupportedFieldsPaymentPayPeriod",
@@ -302,14 +301,6 @@ class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPaySt
302301
name: Optional[bool] = None
303302

304303

305-
class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions(BaseModel):
306-
amount: Optional[bool] = None
307-
308-
currency: Optional[bool] = None
309-
310-
name: Optional[bool] = None
311-
312-
313304
class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsTaxes(BaseModel):
314305
amount: Optional[bool] = None
315306

@@ -335,11 +326,6 @@ class AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPaySt
335326
AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerContributions
336327
] = None
337328

338-
employer_deductions: Optional[
339-
AccountUpdateEventDataAuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions
340-
] = None
341-
"""[DEPRECATED] Use `employer_contributions` instead"""
342-
343329
gross_pay: Optional[bool] = None
344330

345331
individual_id: Optional[bool] = None

src/finch/types/provider.py

-12
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
"AuthenticationMethodSupportedFieldsPayStatementPayStatementsEarnings",
3737
"AuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployeeDeductions",
3838
"AuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerContributions",
39-
"AuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions",
4039
"AuthenticationMethodSupportedFieldsPayStatementPayStatementsTaxes",
4140
"AuthenticationMethodSupportedFieldsPayment",
4241
"AuthenticationMethodSupportedFieldsPaymentPayPeriod",
@@ -297,14 +296,6 @@ class AuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerContri
297296
name: Optional[bool] = None
298297

299298

300-
class AuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions(BaseModel):
301-
amount: Optional[bool] = None
302-
303-
currency: Optional[bool] = None
304-
305-
name: Optional[bool] = None
306-
307-
308299
class AuthenticationMethodSupportedFieldsPayStatementPayStatementsTaxes(BaseModel):
309300
amount: Optional[bool] = None
310301

@@ -326,9 +317,6 @@ class AuthenticationMethodSupportedFieldsPayStatementPayStatements(BaseModel):
326317
AuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerContributions
327318
] = None
328319

329-
employer_deductions: Optional[AuthenticationMethodSupportedFieldsPayStatementPayStatementsEmployerDeductions] = None
330-
"""[DEPRECATED] Use `employer_contributions` instead"""
331-
332320
gross_pay: Optional[bool] = None
333321

334322
individual_id: Optional[bool] = None

tests/test_client.py

+2
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,7 @@ class Model(BaseModel):
809809
[3, "", 0.5],
810810
[2, "", 0.5 * 2.0],
811811
[1, "", 0.5 * 4.0],
812+
[-1100, "", 7.8], # test large number potentially overflowing
812813
],
813814
)
814815
@mock.patch("time.time", mock.MagicMock(return_value=1696004797))
@@ -1686,6 +1687,7 @@ class Model(BaseModel):
16861687
[3, "", 0.5],
16871688
[2, "", 0.5 * 2.0],
16881689
[1, "", 0.5 * 4.0],
1690+
[-1100, "", 7.8], # test large number potentially overflowing
16891691
],
16901692
)
16911693
@mock.patch("time.time", mock.MagicMock(return_value=1696004797))

tests/test_legacy_response.py

+25
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,31 @@ def test_response_parse_mismatched_basemodel(client: Finch) -> None:
3232
response.parse(to=PydanticModel)
3333

3434

35+
@pytest.mark.parametrize(
36+
"content, expected",
37+
[
38+
("false", False),
39+
("true", True),
40+
("False", False),
41+
("True", True),
42+
("TrUe", True),
43+
("FalSe", False),
44+
],
45+
)
46+
def test_response_parse_bool(client: Finch, content: str, expected: bool) -> None:
47+
response = LegacyAPIResponse(
48+
raw=httpx.Response(200, content=content),
49+
client=client,
50+
stream=False,
51+
stream_cls=None,
52+
cast_to=str,
53+
options=FinalRequestOptions.construct(method="get", url="/foo"),
54+
)
55+
56+
result = response.parse(to=bool)
57+
assert result is expected
58+
59+
3560
def test_response_parse_custom_stream(client: Finch) -> None:
3661
response = LegacyAPIResponse(
3762
raw=httpx.Response(200, content=b"foo"),

tests/test_response.py

+50
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,56 @@ async def test_async_response_parse_annotated_type(async_client: AsyncFinch) ->
190190
assert obj.bar == 2
191191

192192

193+
@pytest.mark.parametrize(
194+
"content, expected",
195+
[
196+
("false", False),
197+
("true", True),
198+
("False", False),
199+
("True", True),
200+
("TrUe", True),
201+
("FalSe", False),
202+
],
203+
)
204+
def test_response_parse_bool(client: Finch, content: str, expected: bool) -> None:
205+
response = APIResponse(
206+
raw=httpx.Response(200, content=content),
207+
client=client,
208+
stream=False,
209+
stream_cls=None,
210+
cast_to=str,
211+
options=FinalRequestOptions.construct(method="get", url="/foo"),
212+
)
213+
214+
result = response.parse(to=bool)
215+
assert result is expected
216+
217+
218+
@pytest.mark.parametrize(
219+
"content, expected",
220+
[
221+
("false", False),
222+
("true", True),
223+
("False", False),
224+
("True", True),
225+
("TrUe", True),
226+
("FalSe", False),
227+
],
228+
)
229+
async def test_async_response_parse_bool(client: AsyncFinch, content: str, expected: bool) -> None:
230+
response = AsyncAPIResponse(
231+
raw=httpx.Response(200, content=content),
232+
client=client,
233+
stream=False,
234+
stream_cls=None,
235+
cast_to=str,
236+
options=FinalRequestOptions.construct(method="get", url="/foo"),
237+
)
238+
239+
result = await response.parse(to=bool)
240+
assert result is expected
241+
242+
193243
class OtherModel(BaseModel):
194244
a: str
195245

0 commit comments

Comments
 (0)