isaacus 0.4.0__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
isaacus/_base_client.py CHANGED
@@ -412,8 +412,7 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
412
412
  headers = httpx.Headers(headers_dict)
413
413
 
414
414
  idempotency_header = self._idempotency_header
415
- if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers:
416
- options.idempotency_key = options.idempotency_key or self._idempotency_key()
415
+ if idempotency_header and options.idempotency_key and idempotency_header not in headers:
417
416
  headers[idempotency_header] = options.idempotency_key
418
417
 
419
418
  # Don't set these headers if they were already set or removed by the caller. We check
@@ -878,7 +877,6 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
878
877
  self,
879
878
  cast_to: Type[ResponseT],
880
879
  options: FinalRequestOptions,
881
- remaining_retries: Optional[int] = None,
882
880
  *,
883
881
  stream: Literal[True],
884
882
  stream_cls: Type[_StreamT],
@@ -889,7 +887,6 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
889
887
  self,
890
888
  cast_to: Type[ResponseT],
891
889
  options: FinalRequestOptions,
892
- remaining_retries: Optional[int] = None,
893
890
  *,
894
891
  stream: Literal[False] = False,
895
892
  ) -> ResponseT: ...
@@ -899,7 +896,6 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
899
896
  self,
900
897
  cast_to: Type[ResponseT],
901
898
  options: FinalRequestOptions,
902
- remaining_retries: Optional[int] = None,
903
899
  *,
904
900
  stream: bool = False,
905
901
  stream_cls: Type[_StreamT] | None = None,
@@ -909,125 +905,109 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
909
905
  self,
910
906
  cast_to: Type[ResponseT],
911
907
  options: FinalRequestOptions,
912
- remaining_retries: Optional[int] = None,
913
908
  *,
914
909
  stream: bool = False,
915
910
  stream_cls: type[_StreamT] | None = None,
916
911
  ) -> ResponseT | _StreamT:
917
- if remaining_retries is not None:
918
- retries_taken = options.get_max_retries(self.max_retries) - remaining_retries
919
- else:
920
- retries_taken = 0
921
-
922
- return self._request(
923
- cast_to=cast_to,
924
- options=options,
925
- stream=stream,
926
- stream_cls=stream_cls,
927
- retries_taken=retries_taken,
928
- )
912
+ cast_to = self._maybe_override_cast_to(cast_to, options)
929
913
 
930
- def _request(
931
- self,
932
- *,
933
- cast_to: Type[ResponseT],
934
- options: FinalRequestOptions,
935
- retries_taken: int,
936
- stream: bool,
937
- stream_cls: type[_StreamT] | None,
938
- ) -> ResponseT | _StreamT:
939
914
  # create a copy of the options we were given so that if the
940
915
  # options are mutated later & we then retry, the retries are
941
916
  # given the original options
942
917
  input_options = model_copy(options)
943
-
944
- cast_to = self._maybe_override_cast_to(cast_to, options)
945
- options = self._prepare_options(options)
946
-
947
- remaining_retries = options.get_max_retries(self.max_retries) - retries_taken
948
- request = self._build_request(options, retries_taken=retries_taken)
949
- self._prepare_request(request)
950
-
951
- if options.idempotency_key:
918
+ if input_options.idempotency_key is None and input_options.method.lower() != "get":
952
919
  # ensure the idempotency key is reused between requests
953
- input_options.idempotency_key = options.idempotency_key
920
+ input_options.idempotency_key = self._idempotency_key()
954
921
 
955
- kwargs: HttpxSendArgs = {}
956
- if self.custom_auth is not None:
957
- kwargs["auth"] = self.custom_auth
922
+ response: httpx.Response | None = None
923
+ max_retries = input_options.get_max_retries(self.max_retries)
958
924
 
959
- log.debug("Sending HTTP Request: %s %s", request.method, request.url)
925
+ retries_taken = 0
926
+ for retries_taken in range(max_retries + 1):
927
+ options = model_copy(input_options)
928
+ options = self._prepare_options(options)
960
929
 
961
- try:
962
- response = self._client.send(
963
- request,
964
- stream=stream or self._should_stream_response_body(request=request),
965
- **kwargs,
966
- )
967
- except httpx.TimeoutException as err:
968
- log.debug("Encountered httpx.TimeoutException", exc_info=True)
930
+ remaining_retries = max_retries - retries_taken
931
+ request = self._build_request(options, retries_taken=retries_taken)
932
+ self._prepare_request(request)
969
933
 
970
- if remaining_retries > 0:
971
- return self._retry_request(
972
- input_options,
973
- cast_to,
974
- retries_taken=retries_taken,
975
- stream=stream,
976
- stream_cls=stream_cls,
977
- response_headers=None,
978
- )
934
+ kwargs: HttpxSendArgs = {}
935
+ if self.custom_auth is not None:
936
+ kwargs["auth"] = self.custom_auth
979
937
 
980
- log.debug("Raising timeout error")
981
- raise APITimeoutError(request=request) from err
982
- except Exception as err:
983
- log.debug("Encountered Exception", exc_info=True)
938
+ log.debug("Sending HTTP Request: %s %s", request.method, request.url)
984
939
 
985
- if remaining_retries > 0:
986
- return self._retry_request(
987
- input_options,
988
- cast_to,
989
- retries_taken=retries_taken,
990
- stream=stream,
991
- stream_cls=stream_cls,
992
- response_headers=None,
940
+ response = None
941
+ try:
942
+ response = self._client.send(
943
+ request,
944
+ stream=stream or self._should_stream_response_body(request=request),
945
+ **kwargs,
993
946
  )
947
+ except httpx.TimeoutException as err:
948
+ log.debug("Encountered httpx.TimeoutException", exc_info=True)
949
+
950
+ if remaining_retries > 0:
951
+ self._sleep_for_retry(
952
+ retries_taken=retries_taken,
953
+ max_retries=max_retries,
954
+ options=input_options,
955
+ response=None,
956
+ )
957
+ continue
958
+
959
+ log.debug("Raising timeout error")
960
+ raise APITimeoutError(request=request) from err
961
+ except Exception as err:
962
+ log.debug("Encountered Exception", exc_info=True)
963
+
964
+ if remaining_retries > 0:
965
+ self._sleep_for_retry(
966
+ retries_taken=retries_taken,
967
+ max_retries=max_retries,
968
+ options=input_options,
969
+ response=None,
970
+ )
971
+ continue
972
+
973
+ log.debug("Raising connection error")
974
+ raise APIConnectionError(request=request) from err
975
+
976
+ log.debug(
977
+ 'HTTP Response: %s %s "%i %s" %s',
978
+ request.method,
979
+ request.url,
980
+ response.status_code,
981
+ response.reason_phrase,
982
+ response.headers,
983
+ )
994
984
 
995
- log.debug("Raising connection error")
996
- raise APIConnectionError(request=request) from err
997
-
998
- log.debug(
999
- 'HTTP Response: %s %s "%i %s" %s',
1000
- request.method,
1001
- request.url,
1002
- response.status_code,
1003
- response.reason_phrase,
1004
- response.headers,
1005
- )
985
+ try:
986
+ response.raise_for_status()
987
+ except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
988
+ log.debug("Encountered httpx.HTTPStatusError", exc_info=True)
989
+
990
+ if remaining_retries > 0 and self._should_retry(err.response):
991
+ err.response.close()
992
+ self._sleep_for_retry(
993
+ retries_taken=retries_taken,
994
+ max_retries=max_retries,
995
+ options=input_options,
996
+ response=response,
997
+ )
998
+ continue
1006
999
 
1007
- try:
1008
- response.raise_for_status()
1009
- except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
1010
- log.debug("Encountered httpx.HTTPStatusError", exc_info=True)
1011
-
1012
- if remaining_retries > 0 and self._should_retry(err.response):
1013
- err.response.close()
1014
- return self._retry_request(
1015
- input_options,
1016
- cast_to,
1017
- retries_taken=retries_taken,
1018
- response_headers=err.response.headers,
1019
- stream=stream,
1020
- stream_cls=stream_cls,
1021
- )
1000
+ # If the response is streamed then we need to explicitly read the response
1001
+ # to completion before attempting to access the response text.
1002
+ if not err.response.is_closed:
1003
+ err.response.read()
1022
1004
 
1023
- # If the response is streamed then we need to explicitly read the response
1024
- # to completion before attempting to access the response text.
1025
- if not err.response.is_closed:
1026
- err.response.read()
1005
+ log.debug("Re-raising status error")
1006
+ raise self._make_status_error_from_response(err.response) from None
1027
1007
 
1028
- log.debug("Re-raising status error")
1029
- raise self._make_status_error_from_response(err.response) from None
1008
+ break
1030
1009
 
1010
+ assert response is not None, "could not resolve response (should never happen)"
1031
1011
  return self._process_response(
1032
1012
  cast_to=cast_to,
1033
1013
  options=options,
@@ -1037,37 +1017,20 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1037
1017
  retries_taken=retries_taken,
1038
1018
  )
1039
1019
 
1040
- def _retry_request(
1041
- self,
1042
- options: FinalRequestOptions,
1043
- cast_to: Type[ResponseT],
1044
- *,
1045
- retries_taken: int,
1046
- response_headers: httpx.Headers | None,
1047
- stream: bool,
1048
- stream_cls: type[_StreamT] | None,
1049
- ) -> ResponseT | _StreamT:
1050
- remaining_retries = options.get_max_retries(self.max_retries) - retries_taken
1020
+ def _sleep_for_retry(
1021
+ self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None
1022
+ ) -> None:
1023
+ remaining_retries = max_retries - retries_taken
1051
1024
  if remaining_retries == 1:
1052
1025
  log.debug("1 retry left")
1053
1026
  else:
1054
1027
  log.debug("%i retries left", remaining_retries)
1055
1028
 
1056
- timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers)
1029
+ timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None)
1057
1030
  log.info("Retrying request to %s in %f seconds", options.url, timeout)
1058
1031
 
1059
- # In a synchronous context we are blocking the entire thread. Up to the library user to run the client in a
1060
- # different thread if necessary.
1061
1032
  time.sleep(timeout)
1062
1033
 
1063
- return self._request(
1064
- options=options,
1065
- cast_to=cast_to,
1066
- retries_taken=retries_taken + 1,
1067
- stream=stream,
1068
- stream_cls=stream_cls,
1069
- )
1070
-
1071
1034
  def _process_response(
1072
1035
  self,
1073
1036
  *,
@@ -1411,7 +1374,6 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1411
1374
  options: FinalRequestOptions,
1412
1375
  *,
1413
1376
  stream: Literal[False] = False,
1414
- remaining_retries: Optional[int] = None,
1415
1377
  ) -> ResponseT: ...
1416
1378
 
1417
1379
  @overload
@@ -1422,7 +1384,6 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1422
1384
  *,
1423
1385
  stream: Literal[True],
1424
1386
  stream_cls: type[_AsyncStreamT],
1425
- remaining_retries: Optional[int] = None,
1426
1387
  ) -> _AsyncStreamT: ...
1427
1388
 
1428
1389
  @overload
@@ -1433,7 +1394,6 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1433
1394
  *,
1434
1395
  stream: bool,
1435
1396
  stream_cls: type[_AsyncStreamT] | None = None,
1436
- remaining_retries: Optional[int] = None,
1437
1397
  ) -> ResponseT | _AsyncStreamT: ...
1438
1398
 
1439
1399
  async def request(
@@ -1443,120 +1403,111 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1443
1403
  *,
1444
1404
  stream: bool = False,
1445
1405
  stream_cls: type[_AsyncStreamT] | None = None,
1446
- remaining_retries: Optional[int] = None,
1447
- ) -> ResponseT | _AsyncStreamT:
1448
- if remaining_retries is not None:
1449
- retries_taken = options.get_max_retries(self.max_retries) - remaining_retries
1450
- else:
1451
- retries_taken = 0
1452
-
1453
- return await self._request(
1454
- cast_to=cast_to,
1455
- options=options,
1456
- stream=stream,
1457
- stream_cls=stream_cls,
1458
- retries_taken=retries_taken,
1459
- )
1460
-
1461
- async def _request(
1462
- self,
1463
- cast_to: Type[ResponseT],
1464
- options: FinalRequestOptions,
1465
- *,
1466
- stream: bool,
1467
- stream_cls: type[_AsyncStreamT] | None,
1468
- retries_taken: int,
1469
1406
  ) -> ResponseT | _AsyncStreamT:
1470
1407
  if self._platform is None:
1471
1408
  # `get_platform` can make blocking IO calls so we
1472
1409
  # execute it earlier while we are in an async context
1473
1410
  self._platform = await asyncify(get_platform)()
1474
1411
 
1412
+ cast_to = self._maybe_override_cast_to(cast_to, options)
1413
+
1475
1414
  # create a copy of the options we were given so that if the
1476
1415
  # options are mutated later & we then retry, the retries are
1477
1416
  # given the original options
1478
1417
  input_options = model_copy(options)
1479
-
1480
- cast_to = self._maybe_override_cast_to(cast_to, options)
1481
- options = await self._prepare_options(options)
1482
-
1483
- remaining_retries = options.get_max_retries(self.max_retries) - retries_taken
1484
- request = self._build_request(options, retries_taken=retries_taken)
1485
- await self._prepare_request(request)
1486
-
1487
- if options.idempotency_key:
1418
+ if input_options.idempotency_key is None and input_options.method.lower() != "get":
1488
1419
  # ensure the idempotency key is reused between requests
1489
- input_options.idempotency_key = options.idempotency_key
1420
+ input_options.idempotency_key = self._idempotency_key()
1490
1421
 
1491
- kwargs: HttpxSendArgs = {}
1492
- if self.custom_auth is not None:
1493
- kwargs["auth"] = self.custom_auth
1422
+ response: httpx.Response | None = None
1423
+ max_retries = input_options.get_max_retries(self.max_retries)
1494
1424
 
1495
- try:
1496
- response = await self._client.send(
1497
- request,
1498
- stream=stream or self._should_stream_response_body(request=request),
1499
- **kwargs,
1500
- )
1501
- except httpx.TimeoutException as err:
1502
- log.debug("Encountered httpx.TimeoutException", exc_info=True)
1425
+ retries_taken = 0
1426
+ for retries_taken in range(max_retries + 1):
1427
+ options = model_copy(input_options)
1428
+ options = await self._prepare_options(options)
1503
1429
 
1504
- if remaining_retries > 0:
1505
- return await self._retry_request(
1506
- input_options,
1507
- cast_to,
1508
- retries_taken=retries_taken,
1509
- stream=stream,
1510
- stream_cls=stream_cls,
1511
- response_headers=None,
1512
- )
1430
+ remaining_retries = max_retries - retries_taken
1431
+ request = self._build_request(options, retries_taken=retries_taken)
1432
+ await self._prepare_request(request)
1513
1433
 
1514
- log.debug("Raising timeout error")
1515
- raise APITimeoutError(request=request) from err
1516
- except Exception as err:
1517
- log.debug("Encountered Exception", exc_info=True)
1434
+ kwargs: HttpxSendArgs = {}
1435
+ if self.custom_auth is not None:
1436
+ kwargs["auth"] = self.custom_auth
1518
1437
 
1519
- if remaining_retries > 0:
1520
- return await self._retry_request(
1521
- input_options,
1522
- cast_to,
1523
- retries_taken=retries_taken,
1524
- stream=stream,
1525
- stream_cls=stream_cls,
1526
- response_headers=None,
1527
- )
1438
+ log.debug("Sending HTTP Request: %s %s", request.method, request.url)
1528
1439
 
1529
- log.debug("Raising connection error")
1530
- raise APIConnectionError(request=request) from err
1440
+ response = None
1441
+ try:
1442
+ response = await self._client.send(
1443
+ request,
1444
+ stream=stream or self._should_stream_response_body(request=request),
1445
+ **kwargs,
1446
+ )
1447
+ except httpx.TimeoutException as err:
1448
+ log.debug("Encountered httpx.TimeoutException", exc_info=True)
1449
+
1450
+ if remaining_retries > 0:
1451
+ await self._sleep_for_retry(
1452
+ retries_taken=retries_taken,
1453
+ max_retries=max_retries,
1454
+ options=input_options,
1455
+ response=None,
1456
+ )
1457
+ continue
1458
+
1459
+ log.debug("Raising timeout error")
1460
+ raise APITimeoutError(request=request) from err
1461
+ except Exception as err:
1462
+ log.debug("Encountered Exception", exc_info=True)
1463
+
1464
+ if remaining_retries > 0:
1465
+ await self._sleep_for_retry(
1466
+ retries_taken=retries_taken,
1467
+ max_retries=max_retries,
1468
+ options=input_options,
1469
+ response=None,
1470
+ )
1471
+ continue
1472
+
1473
+ log.debug("Raising connection error")
1474
+ raise APIConnectionError(request=request) from err
1475
+
1476
+ log.debug(
1477
+ 'HTTP Response: %s %s "%i %s" %s',
1478
+ request.method,
1479
+ request.url,
1480
+ response.status_code,
1481
+ response.reason_phrase,
1482
+ response.headers,
1483
+ )
1531
1484
 
1532
- log.debug(
1533
- 'HTTP Request: %s %s "%i %s"', request.method, request.url, response.status_code, response.reason_phrase
1534
- )
1485
+ try:
1486
+ response.raise_for_status()
1487
+ except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
1488
+ log.debug("Encountered httpx.HTTPStatusError", exc_info=True)
1489
+
1490
+ if remaining_retries > 0 and self._should_retry(err.response):
1491
+ await err.response.aclose()
1492
+ await self._sleep_for_retry(
1493
+ retries_taken=retries_taken,
1494
+ max_retries=max_retries,
1495
+ options=input_options,
1496
+ response=response,
1497
+ )
1498
+ continue
1535
1499
 
1536
- try:
1537
- response.raise_for_status()
1538
- except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
1539
- log.debug("Encountered httpx.HTTPStatusError", exc_info=True)
1540
-
1541
- if remaining_retries > 0 and self._should_retry(err.response):
1542
- await err.response.aclose()
1543
- return await self._retry_request(
1544
- input_options,
1545
- cast_to,
1546
- retries_taken=retries_taken,
1547
- response_headers=err.response.headers,
1548
- stream=stream,
1549
- stream_cls=stream_cls,
1550
- )
1500
+ # If the response is streamed then we need to explicitly read the response
1501
+ # to completion before attempting to access the response text.
1502
+ if not err.response.is_closed:
1503
+ await err.response.aread()
1551
1504
 
1552
- # If the response is streamed then we need to explicitly read the response
1553
- # to completion before attempting to access the response text.
1554
- if not err.response.is_closed:
1555
- await err.response.aread()
1505
+ log.debug("Re-raising status error")
1506
+ raise self._make_status_error_from_response(err.response) from None
1556
1507
 
1557
- log.debug("Re-raising status error")
1558
- raise self._make_status_error_from_response(err.response) from None
1508
+ break
1559
1509
 
1510
+ assert response is not None, "could not resolve response (should never happen)"
1560
1511
  return await self._process_response(
1561
1512
  cast_to=cast_to,
1562
1513
  options=options,
@@ -1566,35 +1517,20 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1566
1517
  retries_taken=retries_taken,
1567
1518
  )
1568
1519
 
1569
- async def _retry_request(
1570
- self,
1571
- options: FinalRequestOptions,
1572
- cast_to: Type[ResponseT],
1573
- *,
1574
- retries_taken: int,
1575
- response_headers: httpx.Headers | None,
1576
- stream: bool,
1577
- stream_cls: type[_AsyncStreamT] | None,
1578
- ) -> ResponseT | _AsyncStreamT:
1579
- remaining_retries = options.get_max_retries(self.max_retries) - retries_taken
1520
+ async def _sleep_for_retry(
1521
+ self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None
1522
+ ) -> None:
1523
+ remaining_retries = max_retries - retries_taken
1580
1524
  if remaining_retries == 1:
1581
1525
  log.debug("1 retry left")
1582
1526
  else:
1583
1527
  log.debug("%i retries left", remaining_retries)
1584
1528
 
1585
- timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers)
1529
+ timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None)
1586
1530
  log.info("Retrying request to %s in %f seconds", options.url, timeout)
1587
1531
 
1588
1532
  await anyio.sleep(timeout)
1589
1533
 
1590
- return await self._request(
1591
- options=options,
1592
- cast_to=cast_to,
1593
- retries_taken=retries_taken + 1,
1594
- stream=stream,
1595
- stream_cls=stream_cls,
1596
- )
1597
-
1598
1534
  async def _process_response(
1599
1535
  self,
1600
1536
  *,
isaacus/_client.py CHANGED
@@ -19,10 +19,7 @@ from ._types import (
19
19
  ProxiesTypes,
20
20
  RequestOptions,
21
21
  )
22
- from ._utils import (
23
- is_given,
24
- get_async_library,
25
- )
22
+ from ._utils import is_given, get_async_library
26
23
  from ._version import __version__
27
24
  from .resources import rerankings
28
25
  from ._streaming import Stream as Stream, AsyncStream as AsyncStream
@@ -32,6 +29,7 @@ from ._base_client import (
32
29
  SyncAPIClient,
33
30
  AsyncAPIClient,
34
31
  )
32
+ from .resources.extractions import extractions
35
33
  from .resources.classifications import classifications
36
34
 
37
35
  __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Isaacus", "AsyncIsaacus", "Client", "AsyncClient"]
@@ -40,6 +38,7 @@ __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Isaacus",
40
38
  class Isaacus(SyncAPIClient):
41
39
  classifications: classifications.ClassificationsResource
42
40
  rerankings: rerankings.RerankingsResource
41
+ extractions: extractions.ExtractionsResource
43
42
  with_raw_response: IsaacusWithRawResponse
44
43
  with_streaming_response: IsaacusWithStreamedResponse
45
44
 
@@ -99,6 +98,7 @@ class Isaacus(SyncAPIClient):
99
98
 
100
99
  self.classifications = classifications.ClassificationsResource(self)
101
100
  self.rerankings = rerankings.RerankingsResource(self)
101
+ self.extractions = extractions.ExtractionsResource(self)
102
102
  self.with_raw_response = IsaacusWithRawResponse(self)
103
103
  self.with_streaming_response = IsaacusWithStreamedResponse(self)
104
104
 
@@ -210,6 +210,7 @@ class Isaacus(SyncAPIClient):
210
210
  class AsyncIsaacus(AsyncAPIClient):
211
211
  classifications: classifications.AsyncClassificationsResource
212
212
  rerankings: rerankings.AsyncRerankingsResource
213
+ extractions: extractions.AsyncExtractionsResource
213
214
  with_raw_response: AsyncIsaacusWithRawResponse
214
215
  with_streaming_response: AsyncIsaacusWithStreamedResponse
215
216
 
@@ -269,6 +270,7 @@ class AsyncIsaacus(AsyncAPIClient):
269
270
 
270
271
  self.classifications = classifications.AsyncClassificationsResource(self)
271
272
  self.rerankings = rerankings.AsyncRerankingsResource(self)
273
+ self.extractions = extractions.AsyncExtractionsResource(self)
272
274
  self.with_raw_response = AsyncIsaacusWithRawResponse(self)
273
275
  self.with_streaming_response = AsyncIsaacusWithStreamedResponse(self)
274
276
 
@@ -381,24 +383,28 @@ class IsaacusWithRawResponse:
381
383
  def __init__(self, client: Isaacus) -> None:
382
384
  self.classifications = classifications.ClassificationsResourceWithRawResponse(client.classifications)
383
385
  self.rerankings = rerankings.RerankingsResourceWithRawResponse(client.rerankings)
386
+ self.extractions = extractions.ExtractionsResourceWithRawResponse(client.extractions)
384
387
 
385
388
 
386
389
  class AsyncIsaacusWithRawResponse:
387
390
  def __init__(self, client: AsyncIsaacus) -> None:
388
391
  self.classifications = classifications.AsyncClassificationsResourceWithRawResponse(client.classifications)
389
392
  self.rerankings = rerankings.AsyncRerankingsResourceWithRawResponse(client.rerankings)
393
+ self.extractions = extractions.AsyncExtractionsResourceWithRawResponse(client.extractions)
390
394
 
391
395
 
392
396
  class IsaacusWithStreamedResponse:
393
397
  def __init__(self, client: Isaacus) -> None:
394
398
  self.classifications = classifications.ClassificationsResourceWithStreamingResponse(client.classifications)
395
399
  self.rerankings = rerankings.RerankingsResourceWithStreamingResponse(client.rerankings)
400
+ self.extractions = extractions.ExtractionsResourceWithStreamingResponse(client.extractions)
396
401
 
397
402
 
398
403
  class AsyncIsaacusWithStreamedResponse:
399
404
  def __init__(self, client: AsyncIsaacus) -> None:
400
405
  self.classifications = classifications.AsyncClassificationsResourceWithStreamingResponse(client.classifications)
401
406
  self.rerankings = rerankings.AsyncRerankingsResourceWithStreamingResponse(client.rerankings)
407
+ self.extractions = extractions.AsyncExtractionsResourceWithStreamingResponse(client.extractions)
402
408
 
403
409
 
404
410
  Client = Isaacus
isaacus/_models.py CHANGED
@@ -626,8 +626,8 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any,
626
626
  # Note: if one variant defines an alias then they all should
627
627
  discriminator_alias = field_info.alias
628
628
 
629
- if field_info.annotation and is_literal_type(field_info.annotation):
630
- for entry in get_args(field_info.annotation):
629
+ if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation):
630
+ for entry in get_args(annotation):
631
631
  if isinstance(entry, str):
632
632
  mapping[entry] = variant
633
633
 
isaacus/_response.py CHANGED
@@ -233,7 +233,7 @@ class BaseAPIResponse(Generic[R]):
233
233
  # split is required to handle cases where additional information is included
234
234
  # in the response, e.g. application/json; charset=utf-8
235
235
  content_type, *_ = response.headers.get("content-type", "*").split(";")
236
- if content_type != "application/json":
236
+ if not content_type.endswith("json"):
237
237
  if is_basemodel(cast_to):
238
238
  try:
239
239
  data = response.json()
isaacus/_utils/_utils.py CHANGED
@@ -72,8 +72,16 @@ def _extract_items(
72
72
  from .._files import assert_is_file_content
73
73
 
74
74
  # We have exhausted the path, return the entry we found.
75
- assert_is_file_content(obj, key=flattened_key)
76
75
  assert flattened_key is not None
76
+
77
+ if is_list(obj):
78
+ files: list[tuple[str, FileTypes]] = []
79
+ for entry in obj:
80
+ assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "")
81
+ files.append((flattened_key + "[]", cast(FileTypes, entry)))
82
+ return files
83
+
84
+ assert_is_file_content(obj, key=flattened_key)
77
85
  return [(flattened_key, cast(FileTypes, obj))]
78
86
 
79
87
  index += 1
isaacus/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "isaacus"
4
- __version__ = "0.4.0" # x-release-please-version
4
+ __version__ = "0.6.0" # x-release-please-version