predictorsdk 0.3.0__tar.gz → 0.3.2__tar.gz

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.
Files changed (60) hide show
  1. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/PKG-INFO +1 -1
  2. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/__init__.py +9 -3
  3. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/__init__.py +3 -1
  4. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/http_client.py +1 -2
  5. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/http_sse/_api.py +57 -21
  6. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/jsonable_encoder.py +12 -0
  7. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/errors/__init__.py +3 -3
  8. predictorsdk-0.3.2/predictorsdk/errors/payment_required_error.py +11 -0
  9. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/raw_client.py +62 -17
  10. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/__init__.py +6 -0
  11. predictorsdk-0.3.2/predictorsdk/types/payment_required_error_action.py +5 -0
  12. predictorsdk-0.3.2/predictorsdk/types/payment_required_error_body.py +54 -0
  13. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk.egg-info/PKG-INFO +1 -1
  14. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk.egg-info/SOURCES.txt +3 -1
  15. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/pyproject.toml +1 -1
  16. predictorsdk-0.3.0/predictorsdk/errors/internal_server_error.py +0 -11
  17. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/README.md +0 -0
  18. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/_default_clients.py +0 -0
  19. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/client.py +0 -0
  20. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/api_error.py +0 -0
  21. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/client_wrapper.py +0 -0
  22. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/datetime_utils.py +0 -0
  23. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/file.py +0 -0
  24. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/force_multipart.py +0 -0
  25. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/http_response.py +0 -0
  26. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/http_sse/__init__.py +0 -0
  27. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/http_sse/_decoders.py +0 -0
  28. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/http_sse/_exceptions.py +0 -0
  29. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/http_sse/_models.py +0 -0
  30. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/logging.py +0 -0
  31. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/parse_error.py +0 -0
  32. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/pydantic_utilities.py +0 -0
  33. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/query_encoder.py +0 -0
  34. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/remove_none_from_dict.py +0 -0
  35. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/request_options.py +0 -0
  36. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/core/serialization.py +0 -0
  37. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/environment.py +0 -0
  38. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/errors/bad_gateway_error.py +0 -0
  39. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/errors/bad_request_error.py +0 -0
  40. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/errors/forbidden_error.py +0 -0
  41. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/errors/service_unavailable_error.py +0 -0
  42. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/errors/too_many_requests_error.py +0 -0
  43. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/errors/unauthorized_error.py +0 -0
  44. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/py.typed +0 -0
  45. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/tests/conftest.py +0 -0
  46. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/tests/test_aiohttp_autodetect.py +0 -0
  47. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/crypto_price_item.py +0 -0
  48. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/crypto_prices_response.py +0 -0
  49. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/error_response.py +0 -0
  50. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/markets_list_response.py +0 -0
  51. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/pagination_block.py +0 -0
  52. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/platform_market.py +0 -0
  53. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/platform_market_platform.py +0 -0
  54. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/sports_matching_response.py +0 -0
  55. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/unified_market.py +0 -0
  56. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk/types/unified_market_provider.py +0 -0
  57. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk.egg-info/dependency_links.txt +0 -0
  58. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk.egg-info/requires.txt +0 -0
  59. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/predictorsdk.egg-info/top_level.txt +0 -0
  60. {predictorsdk-0.3.0 → predictorsdk-0.3.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: predictorsdk
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: The official Python client for the PredictorSDK matching markets API
5
5
  Author-email: PredictorSDK <nick@predictorsdk.com>
6
6
  License-Expression: MIT
@@ -12,6 +12,8 @@ if typing.TYPE_CHECKING:
12
12
  ErrorResponse,
13
13
  MarketsListResponse,
14
14
  PaginationBlock,
15
+ PaymentRequiredErrorAction,
16
+ PaymentRequiredErrorBody,
15
17
  PlatformMarket,
16
18
  PlatformMarketPlatform,
17
19
  SportsMatchingResponse,
@@ -22,7 +24,7 @@ if typing.TYPE_CHECKING:
22
24
  BadGatewayError,
23
25
  BadRequestError,
24
26
  ForbiddenError,
25
- InternalServerError,
27
+ PaymentRequiredError,
26
28
  ServiceUnavailableError,
27
29
  TooManyRequestsError,
28
30
  UnauthorizedError,
@@ -40,9 +42,11 @@ _dynamic_imports: typing.Dict[str, str] = {
40
42
  "DefaultAsyncHttpxClient": "._default_clients",
41
43
  "ErrorResponse": ".types",
42
44
  "ForbiddenError": ".errors",
43
- "InternalServerError": ".errors",
44
45
  "MarketsListResponse": ".types",
45
46
  "PaginationBlock": ".types",
47
+ "PaymentRequiredError": ".errors",
48
+ "PaymentRequiredErrorAction": ".types",
49
+ "PaymentRequiredErrorBody": ".types",
46
50
  "PlatformMarket": ".types",
47
51
  "PlatformMarketPlatform": ".types",
48
52
  "PredictorSDK": ".client",
@@ -87,9 +91,11 @@ __all__ = [
87
91
  "DefaultAsyncHttpxClient",
88
92
  "ErrorResponse",
89
93
  "ForbiddenError",
90
- "InternalServerError",
91
94
  "MarketsListResponse",
92
95
  "PaginationBlock",
96
+ "PaymentRequiredError",
97
+ "PaymentRequiredErrorAction",
98
+ "PaymentRequiredErrorBody",
93
99
  "PlatformMarket",
94
100
  "PlatformMarketPlatform",
95
101
  "PredictorSDK",
@@ -12,7 +12,7 @@ if typing.TYPE_CHECKING:
12
12
  from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
13
13
  from .http_client import AsyncHttpClient, HttpClient
14
14
  from .http_response import AsyncHttpResponse, HttpResponse
15
- from .jsonable_encoder import jsonable_encoder
15
+ from .jsonable_encoder import encode_path_param, jsonable_encoder
16
16
  from .logging import ConsoleLogger, ILogger, LogConfig, LogLevel, Logger, create_logger
17
17
  from .parse_error import ParsingError
18
18
  from .pydantic_utilities import (
@@ -53,6 +53,7 @@ _dynamic_imports: typing.Dict[str, str] = {
53
53
  "convert_and_respect_annotation_metadata": ".serialization",
54
54
  "convert_file_dict_to_httpx_tuples": ".file",
55
55
  "create_logger": ".logging",
56
+ "encode_path_param": ".jsonable_encoder",
56
57
  "encode_query": ".query_encoder",
57
58
  "jsonable_encoder": ".jsonable_encoder",
58
59
  "parse_obj_as": ".pydantic_utilities",
@@ -112,6 +113,7 @@ __all__ = [
112
113
  "convert_and_respect_annotation_metadata",
113
114
  "convert_file_dict_to_httpx_tuples",
114
115
  "create_logger",
116
+ "encode_path_param",
115
117
  "encode_query",
116
118
  "jsonable_encoder",
117
119
  "parse_obj_as",
@@ -125,8 +125,7 @@ def _retry_timeout_from_retries(retries: int) -> float:
125
125
 
126
126
 
127
127
  def _should_retry(response: httpx.Response) -> bool:
128
- retryable_400s = [429, 408, 409]
129
- return response.status_code >= 500 or response.status_code in retryable_400s
128
+ return response.status_code >= 500 or response.status_code in [429, 408, 409]
130
129
 
131
130
 
132
131
  _SENSITIVE_HEADERS = frozenset(
@@ -1,8 +1,9 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
+ import codecs
3
4
  import re
4
5
  from contextlib import asynccontextmanager, contextmanager
5
- from typing import Any, AsyncGenerator, AsyncIterator, Iterator, cast
6
+ from typing import Any, AsyncGenerator, AsyncIterator, Iterator
6
7
 
7
8
  import httpx
8
9
  from ._decoders import SSEDecoder
@@ -45,46 +46,81 @@ class EventSource:
45
46
  def response(self) -> httpx.Response:
46
47
  return self._response
47
48
 
49
+ @staticmethod
50
+ def _normalize_sse_line_endings(buf: str) -> str:
51
+ """Normalize line endings per the SSE spec (\\r\\n → \\n, bare \\r → \\n).
52
+
53
+ A trailing \\r is preserved because it may pair with a leading \\n in
54
+ the next chunk to form a single \\r\\n terminator.
55
+ """
56
+ buf = buf.replace("\r\n", "\n")
57
+ if buf.endswith("\r"):
58
+ return buf[:-1].replace("\r", "\n") + "\r"
59
+ return buf.replace("\r", "\n")
60
+
48
61
  def iter_sse(self) -> Iterator[ServerSentEvent]:
49
62
  self._check_content_type()
50
63
  decoder = SSEDecoder()
51
64
  charset = self._get_charset()
65
+ text_decoder = codecs.getincrementaldecoder(charset)(errors="replace")
52
66
 
53
- buffer = ""
67
+ buf = ""
54
68
  for chunk in self._response.iter_bytes():
55
- # Decode chunk using detected charset
56
- text_chunk = chunk.decode(charset, errors="replace")
57
- buffer += text_chunk
58
-
59
- # Process complete lines
60
- while "\n" in buffer:
61
- line, buffer = buffer.split("\n", 1)
62
- line = line.rstrip("\r")
69
+ buf += text_decoder.decode(chunk)
70
+ buf = self._normalize_sse_line_endings(buf)
71
+
72
+ while "\n" in buf:
73
+ line, buf = buf.split("\n", 1)
63
74
  sse = decoder.decode(line)
64
- # when we reach a "\n\n" => line = ''
65
- # => decoder will attempt to return an SSE Event
66
75
  if sse is not None:
67
76
  yield sse
68
77
 
69
- # Process any remaining data in buffer
70
- if buffer.strip():
71
- line = buffer.rstrip("\r")
78
+ # Flush any remaining bytes from the incremental decoder
79
+ buf += text_decoder.decode(b"", final=True)
80
+ buf = buf.replace("\r\n", "\n").replace("\r", "\n")
81
+
82
+ while "\n" in buf:
83
+ line, buf = buf.split("\n", 1)
72
84
  sse = decoder.decode(line)
73
85
  if sse is not None:
74
86
  yield sse
75
87
 
88
+ if buf.strip():
89
+ sse = decoder.decode(buf)
90
+ if sse is not None:
91
+ yield sse
92
+
76
93
  async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]:
77
94
  self._check_content_type()
78
95
  decoder = SSEDecoder()
79
- lines = cast(AsyncGenerator[str, None], self._response.aiter_lines())
80
- try:
81
- async for line in lines:
82
- line = line.rstrip("\n")
96
+ charset = self._get_charset()
97
+ text_decoder = codecs.getincrementaldecoder(charset)(errors="replace")
98
+
99
+ buf = ""
100
+ async for chunk in self._response.aiter_bytes():
101
+ buf += text_decoder.decode(chunk)
102
+ buf = self._normalize_sse_line_endings(buf)
103
+
104
+ while "\n" in buf:
105
+ line, buf = buf.split("\n", 1)
83
106
  sse = decoder.decode(line)
84
107
  if sse is not None:
85
108
  yield sse
86
- finally:
87
- await lines.aclose()
109
+
110
+ # Flush any remaining bytes from the incremental decoder
111
+ buf += text_decoder.decode(b"", final=True)
112
+ buf = buf.replace("\r\n", "\n").replace("\r", "\n")
113
+
114
+ while "\n" in buf:
115
+ line, buf = buf.split("\n", 1)
116
+ sse = decoder.decode(line)
117
+ if sse is not None:
118
+ yield sse
119
+
120
+ if buf.strip():
121
+ sse = decoder.decode(buf)
122
+ if sse is not None:
123
+ yield sse
88
124
 
89
125
 
90
126
  @contextmanager
@@ -106,3 +106,15 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any]
106
106
  return jsonable_encoder(data, custom_encoder=custom_encoder)
107
107
 
108
108
  return to_jsonable_with_fallback(obj, fallback_serializer)
109
+
110
+
111
+ def encode_path_param(obj: Any) -> str:
112
+ """Encode a value for use in a URL path segment.
113
+
114
+ Ensures proper string conversion for all types, including
115
+ booleans which need lowercase 'true'/'false' rather than
116
+ Python's 'True'/'False'.
117
+ """
118
+ if isinstance(obj, bool):
119
+ return "true" if obj else "false"
120
+ return str(jsonable_encoder(obj))
@@ -9,7 +9,7 @@ if typing.TYPE_CHECKING:
9
9
  from .bad_gateway_error import BadGatewayError
10
10
  from .bad_request_error import BadRequestError
11
11
  from .forbidden_error import ForbiddenError
12
- from .internal_server_error import InternalServerError
12
+ from .payment_required_error import PaymentRequiredError
13
13
  from .service_unavailable_error import ServiceUnavailableError
14
14
  from .too_many_requests_error import TooManyRequestsError
15
15
  from .unauthorized_error import UnauthorizedError
@@ -17,7 +17,7 @@ _dynamic_imports: typing.Dict[str, str] = {
17
17
  "BadGatewayError": ".bad_gateway_error",
18
18
  "BadRequestError": ".bad_request_error",
19
19
  "ForbiddenError": ".forbidden_error",
20
- "InternalServerError": ".internal_server_error",
20
+ "PaymentRequiredError": ".payment_required_error",
21
21
  "ServiceUnavailableError": ".service_unavailable_error",
22
22
  "TooManyRequestsError": ".too_many_requests_error",
23
23
  "UnauthorizedError": ".unauthorized_error",
@@ -49,7 +49,7 @@ __all__ = [
49
49
  "BadGatewayError",
50
50
  "BadRequestError",
51
51
  "ForbiddenError",
52
- "InternalServerError",
52
+ "PaymentRequiredError",
53
53
  "ServiceUnavailableError",
54
54
  "TooManyRequestsError",
55
55
  "UnauthorizedError",
@@ -0,0 +1,11 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ from ..core.api_error import ApiError
6
+ from ..types.payment_required_error_body import PaymentRequiredErrorBody
7
+
8
+
9
+ class PaymentRequiredError(ApiError):
10
+ def __init__(self, body: PaymentRequiredErrorBody, headers: typing.Optional[typing.Dict[str, str]] = None):
11
+ super().__init__(status_code=402, headers=headers, body=body)
@@ -12,13 +12,14 @@ from .core.request_options import RequestOptions
12
12
  from .errors.bad_gateway_error import BadGatewayError
13
13
  from .errors.bad_request_error import BadRequestError
14
14
  from .errors.forbidden_error import ForbiddenError
15
- from .errors.internal_server_error import InternalServerError
15
+ from .errors.payment_required_error import PaymentRequiredError
16
16
  from .errors.service_unavailable_error import ServiceUnavailableError
17
17
  from .errors.too_many_requests_error import TooManyRequestsError
18
18
  from .errors.unauthorized_error import UnauthorizedError
19
19
  from .types.crypto_prices_response import CryptoPricesResponse
20
20
  from .types.error_response import ErrorResponse
21
21
  from .types.markets_list_response import MarketsListResponse
22
+ from .types.payment_required_error_body import PaymentRequiredErrorBody
22
23
  from .types.sports_matching_response import SportsMatchingResponse
23
24
  from pydantic import ValidationError
24
25
 
@@ -119,6 +120,17 @@ class RawPredictorSDK:
119
120
  ),
120
121
  ),
121
122
  )
123
+ if _response.status_code == 402:
124
+ raise PaymentRequiredError(
125
+ headers=dict(_response.headers),
126
+ body=typing.cast(
127
+ PaymentRequiredErrorBody,
128
+ parse_obj_as(
129
+ type_=PaymentRequiredErrorBody, # type: ignore
130
+ object_=_response.json(),
131
+ ),
132
+ ),
133
+ )
122
134
  if _response.status_code == 403:
123
135
  raise ForbiddenError(
124
136
  headers=dict(_response.headers),
@@ -228,19 +240,19 @@ class RawPredictorSDK:
228
240
  ),
229
241
  ),
230
242
  )
231
- if _response.status_code == 403:
232
- raise ForbiddenError(
243
+ if _response.status_code == 402:
244
+ raise PaymentRequiredError(
233
245
  headers=dict(_response.headers),
234
246
  body=typing.cast(
235
- ErrorResponse,
247
+ PaymentRequiredErrorBody,
236
248
  parse_obj_as(
237
- type_=ErrorResponse, # type: ignore
249
+ type_=PaymentRequiredErrorBody, # type: ignore
238
250
  object_=_response.json(),
239
251
  ),
240
252
  ),
241
253
  )
242
- if _response.status_code == 429:
243
- raise TooManyRequestsError(
254
+ if _response.status_code == 403:
255
+ raise ForbiddenError(
244
256
  headers=dict(_response.headers),
245
257
  body=typing.cast(
246
258
  ErrorResponse,
@@ -250,8 +262,8 @@ class RawPredictorSDK:
250
262
  ),
251
263
  ),
252
264
  )
253
- if _response.status_code == 500:
254
- raise InternalServerError(
265
+ if _response.status_code == 429:
266
+ raise TooManyRequestsError(
255
267
  headers=dict(_response.headers),
256
268
  body=typing.cast(
257
269
  ErrorResponse,
@@ -363,6 +375,17 @@ class RawPredictorSDK:
363
375
  ),
364
376
  ),
365
377
  )
378
+ if _response.status_code == 402:
379
+ raise PaymentRequiredError(
380
+ headers=dict(_response.headers),
381
+ body=typing.cast(
382
+ PaymentRequiredErrorBody,
383
+ parse_obj_as(
384
+ type_=PaymentRequiredErrorBody, # type: ignore
385
+ object_=_response.json(),
386
+ ),
387
+ ),
388
+ )
366
389
  if _response.status_code == 403:
367
390
  raise ForbiddenError(
368
391
  headers=dict(_response.headers),
@@ -513,6 +536,17 @@ class AsyncRawPredictorSDK:
513
536
  ),
514
537
  ),
515
538
  )
539
+ if _response.status_code == 402:
540
+ raise PaymentRequiredError(
541
+ headers=dict(_response.headers),
542
+ body=typing.cast(
543
+ PaymentRequiredErrorBody,
544
+ parse_obj_as(
545
+ type_=PaymentRequiredErrorBody, # type: ignore
546
+ object_=_response.json(),
547
+ ),
548
+ ),
549
+ )
516
550
  if _response.status_code == 403:
517
551
  raise ForbiddenError(
518
552
  headers=dict(_response.headers),
@@ -622,19 +656,19 @@ class AsyncRawPredictorSDK:
622
656
  ),
623
657
  ),
624
658
  )
625
- if _response.status_code == 403:
626
- raise ForbiddenError(
659
+ if _response.status_code == 402:
660
+ raise PaymentRequiredError(
627
661
  headers=dict(_response.headers),
628
662
  body=typing.cast(
629
- ErrorResponse,
663
+ PaymentRequiredErrorBody,
630
664
  parse_obj_as(
631
- type_=ErrorResponse, # type: ignore
665
+ type_=PaymentRequiredErrorBody, # type: ignore
632
666
  object_=_response.json(),
633
667
  ),
634
668
  ),
635
669
  )
636
- if _response.status_code == 429:
637
- raise TooManyRequestsError(
670
+ if _response.status_code == 403:
671
+ raise ForbiddenError(
638
672
  headers=dict(_response.headers),
639
673
  body=typing.cast(
640
674
  ErrorResponse,
@@ -644,8 +678,8 @@ class AsyncRawPredictorSDK:
644
678
  ),
645
679
  ),
646
680
  )
647
- if _response.status_code == 500:
648
- raise InternalServerError(
681
+ if _response.status_code == 429:
682
+ raise TooManyRequestsError(
649
683
  headers=dict(_response.headers),
650
684
  body=typing.cast(
651
685
  ErrorResponse,
@@ -757,6 +791,17 @@ class AsyncRawPredictorSDK:
757
791
  ),
758
792
  ),
759
793
  )
794
+ if _response.status_code == 402:
795
+ raise PaymentRequiredError(
796
+ headers=dict(_response.headers),
797
+ body=typing.cast(
798
+ PaymentRequiredErrorBody,
799
+ parse_obj_as(
800
+ type_=PaymentRequiredErrorBody, # type: ignore
801
+ object_=_response.json(),
802
+ ),
803
+ ),
804
+ )
760
805
  if _response.status_code == 403:
761
806
  raise ForbiddenError(
762
807
  headers=dict(_response.headers),
@@ -11,6 +11,8 @@ if typing.TYPE_CHECKING:
11
11
  from .error_response import ErrorResponse
12
12
  from .markets_list_response import MarketsListResponse
13
13
  from .pagination_block import PaginationBlock
14
+ from .payment_required_error_action import PaymentRequiredErrorAction
15
+ from .payment_required_error_body import PaymentRequiredErrorBody
14
16
  from .platform_market import PlatformMarket
15
17
  from .platform_market_platform import PlatformMarketPlatform
16
18
  from .sports_matching_response import SportsMatchingResponse
@@ -22,6 +24,8 @@ _dynamic_imports: typing.Dict[str, str] = {
22
24
  "ErrorResponse": ".error_response",
23
25
  "MarketsListResponse": ".markets_list_response",
24
26
  "PaginationBlock": ".pagination_block",
27
+ "PaymentRequiredErrorAction": ".payment_required_error_action",
28
+ "PaymentRequiredErrorBody": ".payment_required_error_body",
25
29
  "PlatformMarket": ".platform_market",
26
30
  "PlatformMarketPlatform": ".platform_market_platform",
27
31
  "SportsMatchingResponse": ".sports_matching_response",
@@ -57,6 +61,8 @@ __all__ = [
57
61
  "ErrorResponse",
58
62
  "MarketsListResponse",
59
63
  "PaginationBlock",
64
+ "PaymentRequiredErrorAction",
65
+ "PaymentRequiredErrorBody",
60
66
  "PlatformMarket",
61
67
  "PlatformMarketPlatform",
62
68
  "SportsMatchingResponse",
@@ -0,0 +1,5 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ PaymentRequiredErrorAction = typing.Union[typing.Literal["upgrade_plan", "resolve_payment"], typing.Any]
@@ -0,0 +1,54 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+ from .payment_required_error_action import PaymentRequiredErrorAction
8
+
9
+
10
+ class PaymentRequiredErrorBody(UniversalBaseModel):
11
+ """
12
+ Error body returned with HTTP 402. The `action` discriminator lets clients route to the correct recovery flow: `upgrade_plan` means the caller is on a lower tier than the endpoint requires, or the Free monthly allowance is exhausted; `resolve_payment` means the caller had a paid subscription that entered a payment-recovery state (past_due/unpaid/paused/incomplete) and the backend has already downgraded them to Free — the fix is in the billing portal, not a new purchase. `required_tier` / `current_tier` are always populated; `included_requests_per_month` and `current_period_requests` are only set when a Free caller hits the monthly allowance.
13
+ """
14
+
15
+ error: str
16
+ message: typing.Optional[str] = pydantic.Field(default=None)
17
+ """
18
+ Additional detail about the error.
19
+ """
20
+
21
+ status_code: int
22
+ action: PaymentRequiredErrorAction = pydantic.Field()
23
+ """
24
+ Recommended client action for this 402.
25
+ """
26
+
27
+ required_tier: str = pydantic.Field()
28
+ """
29
+ Billing tier that would satisfy the gate (e.g. `starter`, `pro`, `business`, `enterprise`).
30
+ """
31
+
32
+ current_tier: str = pydantic.Field()
33
+ """
34
+ Billing tier currently associated with the caller.
35
+ """
36
+
37
+ included_requests_per_month: typing.Optional[int] = pydantic.Field(default=None)
38
+ """
39
+ Monthly Free-tier allowance. Present only when the 402 is caused by the Free cap.
40
+ """
41
+
42
+ current_period_requests: typing.Optional[int] = pydantic.Field(default=None)
43
+ """
44
+ Requests the Free caller has made in the current calendar month. Present only when the 402 is caused by the Free cap.
45
+ """
46
+
47
+ if IS_PYDANTIC_V2:
48
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
49
+ else:
50
+
51
+ class Config:
52
+ frozen = True
53
+ smart_union = True
54
+ extra = pydantic.Extra.allow
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: predictorsdk
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: The official Python client for the PredictorSDK matching markets API
5
5
  Author-email: PredictorSDK <nick@predictorsdk.com>
6
6
  License-Expression: MIT
@@ -36,7 +36,7 @@ predictorsdk/errors/__init__.py
36
36
  predictorsdk/errors/bad_gateway_error.py
37
37
  predictorsdk/errors/bad_request_error.py
38
38
  predictorsdk/errors/forbidden_error.py
39
- predictorsdk/errors/internal_server_error.py
39
+ predictorsdk/errors/payment_required_error.py
40
40
  predictorsdk/errors/service_unavailable_error.py
41
41
  predictorsdk/errors/too_many_requests_error.py
42
42
  predictorsdk/errors/unauthorized_error.py
@@ -48,6 +48,8 @@ predictorsdk/types/crypto_prices_response.py
48
48
  predictorsdk/types/error_response.py
49
49
  predictorsdk/types/markets_list_response.py
50
50
  predictorsdk/types/pagination_block.py
51
+ predictorsdk/types/payment_required_error_action.py
52
+ predictorsdk/types/payment_required_error_body.py
51
53
  predictorsdk/types/platform_market.py
52
54
  predictorsdk/types/platform_market_platform.py
53
55
  predictorsdk/types/sports_matching_response.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "predictorsdk"
7
- version = "0.3.0"
7
+ version = "0.3.2"
8
8
  description = "The official Python client for the PredictorSDK matching markets API"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,11 +0,0 @@
1
- # This file was auto-generated by Fern from our API Definition.
2
-
3
- import typing
4
-
5
- from ..core.api_error import ApiError
6
- from ..types.error_response import ErrorResponse
7
-
8
-
9
- class InternalServerError(ApiError):
10
- def __init__(self, body: ErrorResponse, headers: typing.Optional[typing.Dict[str, str]] = None):
11
- super().__init__(status_code=500, headers=headers, body=body)
File without changes
File without changes