Skip to content

Commit 6f6c4a1

Browse files
chore(internal): move error classes from _base_exceptions to _exceptions (⚠️ breaking) (#107)
## Migration Guide If you were instantiating our error classes directly, you may no longer pass a `request` kwarg (it is now pulled from the `response`). ```diff # before: - BadRequestError("Test", response=response, request=request) # after: + BadRequestError("Test", response=response) ```
1 parent 6cced26 commit 6f6c4a1

File tree

6 files changed

+212
-191
lines changed

6 files changed

+212
-191
lines changed

src/finch/__init__.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,18 @@
3939
"Transport",
4040
"ProxiesTypes",
4141
"APIError",
42-
"APIConnectionError",
43-
"APIResponseValidationError",
4442
"APIStatusError",
4543
"APITimeoutError",
46-
"AuthenticationError",
44+
"APIConnectionError",
45+
"APIResponseValidationError",
4746
"BadRequestError",
48-
"ConflictError",
49-
"InternalServerError",
50-
"NotFoundError",
47+
"AuthenticationError",
5148
"PermissionDeniedError",
52-
"RateLimitError",
49+
"NotFoundError",
50+
"ConflictError",
5351
"UnprocessableEntityError",
52+
"RateLimitError",
53+
"InternalServerError",
5454
"Timeout",
5555
"RequestOptions",
5656
"Client",
@@ -65,7 +65,7 @@
6565
# Update the __module__ attribute for exported symbols so that
6666
# error messages point to this module instead of the module
6767
# it was originally defined in, e.g.
68-
# finch._base_exceptions.NotFoundError -> finch.NotFoundError
68+
# finch._exceptions.NotFoundError -> finch.NotFoundError
6969
__locals = locals()
7070
for __name in __all__:
7171
if not __name.startswith("__"):

src/finch/_base_client.py

+16-40
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from httpx import URL, Limits
3434
from pydantic import PrivateAttr
3535

36-
from . import _base_exceptions as exceptions
36+
from . import _exceptions
3737
from ._qs import Querystring
3838
from ._types import (
3939
NOT_GIVEN,
@@ -64,7 +64,7 @@
6464
construct_type,
6565
)
6666
from ._streaming import Stream, AsyncStream
67-
from ._base_exceptions import (
67+
from ._exceptions import (
6868
APIStatusError,
6969
APITimeoutError,
7070
APIConnectionError,
@@ -335,7 +335,6 @@ def __init__(
335335

336336
def _make_status_error_from_response(
337337
self,
338-
request: httpx.Request,
339338
response: httpx.Response,
340339
) -> APIStatusError:
341340
err_text = response.text.strip()
@@ -347,33 +346,16 @@ def _make_status_error_from_response(
347346
except Exception:
348347
err_msg = err_text or f"Error code: {response.status_code}"
349348

350-
return self._make_status_error(err_msg, body=body, request=request, response=response)
349+
return self._make_status_error(err_msg, body=body, response=response)
351350

352351
def _make_status_error(
353352
self,
354353
err_msg: str,
355354
*,
356355
body: object,
357-
request: httpx.Request,
358356
response: httpx.Response,
359-
) -> APIStatusError:
360-
if response.status_code == 400:
361-
return exceptions.BadRequestError(err_msg, request=request, response=response, body=body)
362-
if response.status_code == 401:
363-
return exceptions.AuthenticationError(err_msg, request=request, response=response, body=body)
364-
if response.status_code == 403:
365-
return exceptions.PermissionDeniedError(err_msg, request=request, response=response, body=body)
366-
if response.status_code == 404:
367-
return exceptions.NotFoundError(err_msg, request=request, response=response, body=body)
368-
if response.status_code == 409:
369-
return exceptions.ConflictError(err_msg, request=request, response=response, body=body)
370-
if response.status_code == 422:
371-
return exceptions.UnprocessableEntityError(err_msg, request=request, response=response, body=body)
372-
if response.status_code == 429:
373-
return exceptions.RateLimitError(err_msg, request=request, response=response, body=body)
374-
if response.status_code >= 500:
375-
return exceptions.InternalServerError(err_msg, request=request, response=response, body=body)
376-
return APIStatusError(err_msg, request=request, response=response, body=body)
357+
) -> _exceptions.APIStatusError:
358+
raise NotImplementedError()
377359

378360
def _remaining_retries(
379361
self,
@@ -532,10 +514,10 @@ def _process_response(
532514
content_type, *_ = response.headers.get("content-type").split(";")
533515
if content_type != "application/json":
534516
if self._strict_response_validation:
535-
raise exceptions.APIResponseValidationError(
517+
raise APIResponseValidationError(
536518
response=response,
537-
request=response.request,
538519
message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.",
520+
body=response.text,
539521
)
540522

541523
# If the API responds with content that isn't JSON then we just return
@@ -544,7 +526,11 @@ def _process_response(
544526
return response.text # type: ignore
545527

546528
data = response.json()
547-
return self._process_response_data(data=data, cast_to=cast_to, response=response)
529+
530+
try:
531+
return self._process_response_data(data=data, cast_to=cast_to, response=response)
532+
except pydantic.ValidationError as err:
533+
raise APIResponseValidationError(response=response, body=data) from err
548534

549535
def _process_response_data(
550536
self,
@@ -826,7 +812,7 @@ def _request(
826812
# If the response is streamed then we need to explicitly read the response
827813
# to completion before attempting to access the response text.
828814
err.response.read()
829-
raise self._make_status_error_from_response(request, err.response) from None
815+
raise self._make_status_error_from_response(err.response) from None
830816
except httpx.TimeoutException as err:
831817
if retries > 0:
832818
return self._retry_request(options, cast_to, retries, stream=stream, stream_cls=stream_cls)
@@ -845,12 +831,7 @@ def _request(
845831
raise MissingStreamClassError()
846832
return stream_cls(cast_to=cast_to, response=response, client=self)
847833

848-
try:
849-
rsp = self._process_response(cast_to=cast_to, options=options, response=response)
850-
except pydantic.ValidationError as err:
851-
raise APIResponseValidationError(request=request, response=response) from err
852-
853-
return rsp
834+
return self._process_response(cast_to=cast_to, options=options, response=response)
854835

855836
def _retry_request(
856837
self,
@@ -1184,7 +1165,7 @@ async def _request(
11841165
# If the response is streamed then we need to explicitly read the response
11851166
# to completion before attempting to access the response text.
11861167
await err.response.aread()
1187-
raise self._make_status_error_from_response(request, err.response) from None
1168+
raise self._make_status_error_from_response(err.response) from None
11881169
except httpx.ConnectTimeout as err:
11891170
if retries > 0:
11901171
return await self._retry_request(options, cast_to, retries, stream=stream, stream_cls=stream_cls)
@@ -1213,12 +1194,7 @@ async def _request(
12131194
raise MissingStreamClassError()
12141195
return stream_cls(cast_to=cast_to, response=response, client=self)
12151196

1216-
try:
1217-
rsp = self._process_response(cast_to=cast_to, options=options, response=response)
1218-
except pydantic.ValidationError as err:
1219-
raise APIResponseValidationError(request=request, response=response) from err
1220-
1221-
return rsp
1197+
return self._process_response(cast_to=cast_to, options=options, response=response)
12221198

12231199
async def _retry_request(
12241200
self,

src/finch/_base_exceptions.py

-119
This file was deleted.

src/finch/_client.py

+66-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import httpx
1010

11-
from . import resources
11+
from . import resources, _exceptions
1212
from ._qs import Querystring
1313
from ._types import (
1414
NOT_GIVEN,
@@ -23,6 +23,7 @@
2323
from ._version import __version__
2424
from ._streaming import Stream as Stream
2525
from ._streaming import AsyncStream as AsyncStream
26+
from ._exceptions import APIStatusError
2627
from ._base_client import (
2728
DEFAULT_LIMITS,
2829
DEFAULT_TIMEOUT,
@@ -274,6 +275,38 @@ def get_auth_url(
274275
)
275276
)
276277

278+
def _make_status_error(
279+
self,
280+
err_msg: str,
281+
*,
282+
body: object,
283+
response: httpx.Response,
284+
) -> APIStatusError:
285+
if response.status_code == 400:
286+
return _exceptions.BadRequestError(err_msg, response=response, body=body)
287+
288+
if response.status_code == 401:
289+
return _exceptions.AuthenticationError(err_msg, response=response, body=body)
290+
291+
if response.status_code == 403:
292+
return _exceptions.PermissionDeniedError(err_msg, response=response, body=body)
293+
294+
if response.status_code == 404:
295+
return _exceptions.NotFoundError(err_msg, response=response, body=body)
296+
297+
if response.status_code == 409:
298+
return _exceptions.ConflictError(err_msg, response=response, body=body)
299+
300+
if response.status_code == 422:
301+
return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body)
302+
303+
if response.status_code == 429:
304+
return _exceptions.RateLimitError(err_msg, response=response, body=body)
305+
306+
if response.status_code >= 500:
307+
return _exceptions.InternalServerError(err_msg, response=response, body=body)
308+
return APIStatusError(err_msg, response=response, body=body)
309+
277310

278311
class AsyncFinch(AsyncAPIClient):
279312
hris: resources.AsyncHRIS
@@ -508,6 +541,38 @@ def get_auth_url(
508541
)
509542
)
510543

544+
def _make_status_error(
545+
self,
546+
err_msg: str,
547+
*,
548+
body: object,
549+
response: httpx.Response,
550+
) -> APIStatusError:
551+
if response.status_code == 400:
552+
return _exceptions.BadRequestError(err_msg, response=response, body=body)
553+
554+
if response.status_code == 401:
555+
return _exceptions.AuthenticationError(err_msg, response=response, body=body)
556+
557+
if response.status_code == 403:
558+
return _exceptions.PermissionDeniedError(err_msg, response=response, body=body)
559+
560+
if response.status_code == 404:
561+
return _exceptions.NotFoundError(err_msg, response=response, body=body)
562+
563+
if response.status_code == 409:
564+
return _exceptions.ConflictError(err_msg, response=response, body=body)
565+
566+
if response.status_code == 422:
567+
return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body)
568+
569+
if response.status_code == 429:
570+
return _exceptions.RateLimitError(err_msg, response=response, body=body)
571+
572+
if response.status_code >= 500:
573+
return _exceptions.InternalServerError(err_msg, response=response, body=body)
574+
return APIStatusError(err_msg, response=response, body=body)
575+
511576

512577
Client = Finch
513578

0 commit comments

Comments
 (0)