sarvamai 0.1.5a5__py3-none-any.whl → 0.1.5a6__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.
Files changed (93) hide show
  1. sarvamai/__init__.py +1 -45
  2. sarvamai/chat/__init__.py +0 -2
  3. sarvamai/chat/client.py +10 -9
  4. sarvamai/chat/raw_client.py +37 -48
  5. sarvamai/client.py +31 -13
  6. sarvamai/core/__init__.py +0 -5
  7. sarvamai/core/api_error.py +5 -13
  8. sarvamai/core/client_wrapper.py +20 -17
  9. sarvamai/core/http_client.py +24 -70
  10. sarvamai/core/http_response.py +11 -19
  11. sarvamai/core/pydantic_utilities.py +108 -69
  12. sarvamai/environment.py +3 -10
  13. sarvamai/errors/__init__.py +0 -2
  14. sarvamai/errors/bad_request_error.py +3 -4
  15. sarvamai/errors/forbidden_error.py +3 -4
  16. sarvamai/errors/internal_server_error.py +3 -4
  17. sarvamai/errors/service_unavailable_error.py +2 -4
  18. sarvamai/errors/too_many_requests_error.py +3 -4
  19. sarvamai/errors/unprocessable_entity_error.py +3 -4
  20. sarvamai/requests/__init__.py +0 -18
  21. sarvamai/requests/chat_completion_request_message.py +1 -3
  22. sarvamai/requests/create_chat_completion_response.py +2 -2
  23. sarvamai/requests/diarized_transcript.py +1 -2
  24. sarvamai/requests/error_details.py +1 -0
  25. sarvamai/requests/language_identification_response.py +1 -0
  26. sarvamai/requests/speech_to_text_response.py +2 -1
  27. sarvamai/requests/speech_to_text_translate_response.py +1 -0
  28. sarvamai/requests/text_to_speech_response.py +2 -2
  29. sarvamai/requests/timestamps_model.py +1 -2
  30. sarvamai/requests/translation_response.py +1 -0
  31. sarvamai/requests/transliteration_response.py +1 -0
  32. sarvamai/speech_to_text/__init__.py +0 -2
  33. sarvamai/speech_to_text/client.py +14 -13
  34. sarvamai/speech_to_text/raw_client.py +68 -99
  35. sarvamai/text/__init__.py +0 -2
  36. sarvamai/text/client.py +25 -24
  37. sarvamai/text/raw_client.py +91 -126
  38. sarvamai/text_to_speech/__init__.py +0 -2
  39. sarvamai/text_to_speech/client.py +11 -10
  40. sarvamai/text_to_speech/raw_client.py +38 -49
  41. sarvamai/types/__init__.py +0 -24
  42. sarvamai/types/chat_completion_request_assistant_message.py +3 -3
  43. sarvamai/types/chat_completion_request_message.py +2 -3
  44. sarvamai/types/chat_completion_request_system_message.py +3 -3
  45. sarvamai/types/chat_completion_request_user_message.py +3 -3
  46. sarvamai/types/chat_completion_response_message.py +3 -3
  47. sarvamai/types/choice.py +4 -4
  48. sarvamai/types/completion_usage.py +3 -3
  49. sarvamai/types/create_chat_completion_response.py +3 -3
  50. sarvamai/types/diarized_entry.py +3 -3
  51. sarvamai/types/diarized_transcript.py +3 -3
  52. sarvamai/types/error_details.py +3 -3
  53. sarvamai/types/error_message.py +4 -4
  54. sarvamai/types/language_identification_response.py +2 -2
  55. sarvamai/types/speech_to_text_response.py +3 -3
  56. sarvamai/types/speech_to_text_translate_response.py +3 -3
  57. sarvamai/types/text_to_speech_response.py +2 -2
  58. sarvamai/types/timestamps_model.py +2 -2
  59. sarvamai/types/translation_response.py +2 -2
  60. sarvamai/types/transliteration_response.py +2 -2
  61. sarvamai-0.1.5a6.dist-info/METADATA +174 -0
  62. sarvamai-0.1.5a6.dist-info/RECORD +106 -0
  63. sarvamai/core/events.py +0 -30
  64. sarvamai/core/force_multipart.py +0 -16
  65. sarvamai/requests/audio_data.py +0 -21
  66. sarvamai/requests/audio_message.py +0 -8
  67. sarvamai/requests/error_data.py +0 -15
  68. sarvamai/requests/events_data.py +0 -17
  69. sarvamai/requests/speech_to_text_streaming_response.py +0 -10
  70. sarvamai/requests/speech_to_text_streaming_response_data.py +0 -9
  71. sarvamai/requests/transcription_data.py +0 -35
  72. sarvamai/requests/transcription_metrics.py +0 -15
  73. sarvamai/speech_to_text_streaming/__init__.py +0 -7
  74. sarvamai/speech_to_text_streaming/client.py +0 -189
  75. sarvamai/speech_to_text_streaming/raw_client.py +0 -166
  76. sarvamai/speech_to_text_streaming/socket_client.py +0 -129
  77. sarvamai/speech_to_text_streaming/types/__init__.py +0 -8
  78. sarvamai/speech_to_text_streaming/types/speech_to_text_streaming_language_code.py +0 -8
  79. sarvamai/speech_to_text_streaming/types/speech_to_text_streaming_model.py +0 -5
  80. sarvamai/types/audio_data.py +0 -33
  81. sarvamai/types/audio_data_encoding.py +0 -5
  82. sarvamai/types/audio_message.py +0 -20
  83. sarvamai/types/error_data.py +0 -27
  84. sarvamai/types/events_data.py +0 -28
  85. sarvamai/types/format.py +0 -5
  86. sarvamai/types/speech_to_text_streaming_response.py +0 -22
  87. sarvamai/types/speech_to_text_streaming_response_data.py +0 -9
  88. sarvamai/types/speech_to_text_streaming_response_type.py +0 -5
  89. sarvamai/types/transcription_data.py +0 -45
  90. sarvamai/types/transcription_metrics.py +0 -27
  91. sarvamai-0.1.5a5.dist-info/METADATA +0 -28
  92. sarvamai-0.1.5a5.dist-info/RECORD +0 -134
  93. {sarvamai-0.1.5a5.dist-info → sarvamai-0.1.5a6.dist-info}/WHEEL +0 -0
@@ -11,12 +11,10 @@ from random import random
11
11
 
12
12
  import httpx
13
13
  from .file import File, convert_file_dict_to_httpx_tuples
14
- from .force_multipart import FORCE_MULTIPART
15
14
  from .jsonable_encoder import jsonable_encoder
16
15
  from .query_encoder import encode_query
17
16
  from .remove_none_from_dict import remove_none_from_dict
18
17
  from .request_options import RequestOptions
19
- from httpx._types import RequestFiles
20
18
 
21
19
  INITIAL_RETRY_DELAY_SECONDS = 0.5
22
20
  MAX_RETRY_DELAY_SECONDS = 10
@@ -180,17 +178,11 @@ class HttpClient:
180
178
  json: typing.Optional[typing.Any] = None,
181
179
  data: typing.Optional[typing.Any] = None,
182
180
  content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
183
- files: typing.Optional[
184
- typing.Union[
185
- typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
186
- typing.List[typing.Tuple[str, File]],
187
- ]
188
- ] = None,
181
+ files: typing.Optional[typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]]] = None,
189
182
  headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
190
183
  request_options: typing.Optional[RequestOptions] = None,
191
184
  retries: int = 2,
192
185
  omit: typing.Optional[typing.Any] = None,
193
- force_multipart: typing.Optional[bool] = None,
194
186
  ) -> httpx.Response:
195
187
  base_url = self.get_base_url(base_url)
196
188
  timeout = (
@@ -201,15 +193,6 @@ class HttpClient:
201
193
 
202
194
  json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
203
195
 
204
- request_files: typing.Optional[RequestFiles] = (
205
- convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
206
- if (files is not None and files is not omit and isinstance(files, dict))
207
- else None
208
- )
209
-
210
- if (request_files is None or len(request_files) == 0) and force_multipart:
211
- request_files = FORCE_MULTIPART
212
-
213
196
  response = self.httpx_client.request(
214
197
  method=method,
215
198
  url=urllib.parse.urljoin(f"{base_url}/", path),
@@ -242,7 +225,11 @@ class HttpClient:
242
225
  json=json_body,
243
226
  data=data_body,
244
227
  content=content,
245
- files=request_files,
228
+ files=(
229
+ convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
230
+ if (files is not None and files is not omit)
231
+ else None
232
+ ),
246
233
  timeout=timeout,
247
234
  )
248
235
 
@@ -277,17 +264,11 @@ class HttpClient:
277
264
  json: typing.Optional[typing.Any] = None,
278
265
  data: typing.Optional[typing.Any] = None,
279
266
  content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
280
- files: typing.Optional[
281
- typing.Union[
282
- typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
283
- typing.List[typing.Tuple[str, File]],
284
- ]
285
- ] = None,
267
+ files: typing.Optional[typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]]] = None,
286
268
  headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
287
269
  request_options: typing.Optional[RequestOptions] = None,
288
270
  retries: int = 2,
289
271
  omit: typing.Optional[typing.Any] = None,
290
- force_multipart: typing.Optional[bool] = None,
291
272
  ) -> typing.Iterator[httpx.Response]:
292
273
  base_url = self.get_base_url(base_url)
293
274
  timeout = (
@@ -296,15 +277,6 @@ class HttpClient:
296
277
  else self.base_timeout()
297
278
  )
298
279
 
299
- request_files: typing.Optional[RequestFiles] = (
300
- convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
301
- if (files is not None and files is not omit and isinstance(files, dict))
302
- else None
303
- )
304
-
305
- if (request_files is None or len(request_files) == 0) and force_multipart:
306
- request_files = FORCE_MULTIPART
307
-
308
280
  json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
309
281
 
310
282
  with self.httpx_client.stream(
@@ -339,7 +311,11 @@ class HttpClient:
339
311
  json=json_body,
340
312
  data=data_body,
341
313
  content=content,
342
- files=request_files,
314
+ files=(
315
+ convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
316
+ if (files is not None and files is not omit)
317
+ else None
318
+ ),
343
319
  timeout=timeout,
344
320
  ) as stream:
345
321
  yield stream
@@ -378,17 +354,11 @@ class AsyncHttpClient:
378
354
  json: typing.Optional[typing.Any] = None,
379
355
  data: typing.Optional[typing.Any] = None,
380
356
  content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
381
- files: typing.Optional[
382
- typing.Union[
383
- typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
384
- typing.List[typing.Tuple[str, File]],
385
- ]
386
- ] = None,
357
+ files: typing.Optional[typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]]] = None,
387
358
  headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
388
359
  request_options: typing.Optional[RequestOptions] = None,
389
360
  retries: int = 2,
390
361
  omit: typing.Optional[typing.Any] = None,
391
- force_multipart: typing.Optional[bool] = None,
392
362
  ) -> httpx.Response:
393
363
  base_url = self.get_base_url(base_url)
394
364
  timeout = (
@@ -397,15 +367,6 @@ class AsyncHttpClient:
397
367
  else self.base_timeout()
398
368
  )
399
369
 
400
- request_files: typing.Optional[RequestFiles] = (
401
- convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
402
- if (files is not None and files is not omit and isinstance(files, dict))
403
- else None
404
- )
405
-
406
- if (request_files is None or len(request_files) == 0) and force_multipart:
407
- request_files = FORCE_MULTIPART
408
-
409
370
  json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
410
371
 
411
372
  # Add the input to each of these and do None-safety checks
@@ -441,7 +402,11 @@ class AsyncHttpClient:
441
402
  json=json_body,
442
403
  data=data_body,
443
404
  content=content,
444
- files=request_files,
405
+ files=(
406
+ convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
407
+ if files is not None
408
+ else None
409
+ ),
445
410
  timeout=timeout,
446
411
  )
447
412
 
@@ -475,17 +440,11 @@ class AsyncHttpClient:
475
440
  json: typing.Optional[typing.Any] = None,
476
441
  data: typing.Optional[typing.Any] = None,
477
442
  content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
478
- files: typing.Optional[
479
- typing.Union[
480
- typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
481
- typing.List[typing.Tuple[str, File]],
482
- ]
483
- ] = None,
443
+ files: typing.Optional[typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]]] = None,
484
444
  headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
485
445
  request_options: typing.Optional[RequestOptions] = None,
486
446
  retries: int = 2,
487
447
  omit: typing.Optional[typing.Any] = None,
488
- force_multipart: typing.Optional[bool] = None,
489
448
  ) -> typing.AsyncIterator[httpx.Response]:
490
449
  base_url = self.get_base_url(base_url)
491
450
  timeout = (
@@ -494,15 +453,6 @@ class AsyncHttpClient:
494
453
  else self.base_timeout()
495
454
  )
496
455
 
497
- request_files: typing.Optional[RequestFiles] = (
498
- convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
499
- if (files is not None and files is not omit and isinstance(files, dict))
500
- else None
501
- )
502
-
503
- if (request_files is None or len(request_files) == 0) and force_multipart:
504
- request_files = FORCE_MULTIPART
505
-
506
456
  json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
507
457
 
508
458
  async with self.httpx_client.stream(
@@ -537,7 +487,11 @@ class AsyncHttpClient:
537
487
  json=json_body,
538
488
  data=data_body,
539
489
  content=content,
540
- files=request_files,
490
+ files=(
491
+ convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
492
+ if files is not None
493
+ else None
494
+ ),
541
495
  timeout=timeout,
542
496
  ) as stream:
543
497
  yield stream
@@ -5,31 +5,20 @@ from typing import Dict, Generic, TypeVar
5
5
  import httpx
6
6
 
7
7
  T = TypeVar("T")
8
- """Generic to represent the underlying type of the data wrapped by the HTTP response."""
9
8
 
10
9
 
11
- class BaseHttpResponse:
12
- """Minimalist HTTP response wrapper that exposes response headers."""
13
-
10
+ class HttpResponse(Generic[T]):
14
11
  _response: httpx.Response
12
+ _data: T
15
13
 
16
- def __init__(self, response: httpx.Response):
14
+ def __init__(self, response: httpx.Response, data: T):
17
15
  self._response = response
16
+ self._data = data
18
17
 
19
18
  @property
20
19
  def headers(self) -> Dict[str, str]:
21
20
  return dict(self._response.headers)
22
21
 
23
-
24
- class HttpResponse(Generic[T], BaseHttpResponse):
25
- """HTTP response wrapper that exposes response headers and data."""
26
-
27
- _data: T
28
-
29
- def __init__(self, response: httpx.Response, data: T):
30
- super().__init__(response)
31
- self._data = data
32
-
33
22
  @property
34
23
  def data(self) -> T:
35
24
  return self._data
@@ -38,15 +27,18 @@ class HttpResponse(Generic[T], BaseHttpResponse):
38
27
  self._response.close()
39
28
 
40
29
 
41
- class AsyncHttpResponse(Generic[T], BaseHttpResponse):
42
- """HTTP response wrapper that exposes response headers and data."""
43
-
30
+ class AsyncHttpResponse(Generic[T]):
31
+ _response: httpx.Response
44
32
  _data: T
45
33
 
46
34
  def __init__(self, response: httpx.Response, data: T):
47
- super().__init__(response)
35
+ self._response = response
48
36
  self._data = data
49
37
 
38
+ @property
39
+ def headers(self) -> Dict[str, str]:
40
+ return dict(self._response.headers)
41
+
50
42
  @property
51
43
  def data(self) -> T:
52
44
  return self._data
@@ -2,65 +2,87 @@
2
2
 
3
3
  # nopycln: file
4
4
  import datetime as dt
5
+ import typing
5
6
  from collections import defaultdict
6
- from typing import Any, Callable, ClassVar, Dict, List, Mapping, Optional, Set, Tuple, Type, TypeVar, Union, cast
7
7
 
8
8
  import pydantic
9
+ import typing_extensions
10
+ from .datetime_utils import serialize_datetime
11
+ from .serialization import convert_and_respect_annotation_metadata
9
12
 
10
13
  IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
11
14
 
12
15
  if IS_PYDANTIC_V2:
13
- from pydantic.v1.datetime_parse import parse_date as parse_date
14
- from pydantic.v1.datetime_parse import parse_datetime as parse_datetime
15
- from pydantic.v1.fields import ModelField as ModelField
16
- from pydantic.v1.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[attr-defined]
17
- from pydantic.v1.typing import get_args as get_args
18
- from pydantic.v1.typing import get_origin as get_origin
19
- from pydantic.v1.typing import is_literal_type as is_literal_type
20
- from pydantic.v1.typing import is_union as is_union
16
+ # isort will try to reformat the comments on these imports, which breaks mypy
17
+ # isort: off
18
+ from pydantic.v1.datetime_parse import ( # type: ignore # pyright: ignore[reportMissingImports] # Pydantic v2
19
+ parse_date as parse_date,
20
+ )
21
+ from pydantic.v1.datetime_parse import ( # pyright: ignore[reportMissingImports] # Pydantic v2
22
+ parse_datetime as parse_datetime,
23
+ )
24
+ from pydantic.v1.json import ( # type: ignore # pyright: ignore[reportMissingImports] # Pydantic v2
25
+ ENCODERS_BY_TYPE as encoders_by_type,
26
+ )
27
+ from pydantic.v1.typing import ( # type: ignore # pyright: ignore[reportMissingImports] # Pydantic v2
28
+ get_args as get_args,
29
+ )
30
+ from pydantic.v1.typing import ( # pyright: ignore[reportMissingImports] # Pydantic v2
31
+ get_origin as get_origin,
32
+ )
33
+ from pydantic.v1.typing import ( # pyright: ignore[reportMissingImports] # Pydantic v2
34
+ is_literal_type as is_literal_type,
35
+ )
36
+ from pydantic.v1.typing import ( # pyright: ignore[reportMissingImports] # Pydantic v2
37
+ is_union as is_union,
38
+ )
39
+ from pydantic.v1.fields import ModelField as ModelField # type: ignore # pyright: ignore[reportMissingImports] # Pydantic v2
21
40
  else:
22
- from pydantic.datetime_parse import parse_date as parse_date # type: ignore[no-redef]
23
- from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore[no-redef]
24
- from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef]
25
- from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[no-redef]
26
- from pydantic.typing import get_args as get_args # type: ignore[no-redef]
27
- from pydantic.typing import get_origin as get_origin # type: ignore[no-redef]
28
- from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef]
29
- from pydantic.typing import is_union as is_union # type: ignore[no-redef]
41
+ from pydantic.datetime_parse import parse_date as parse_date # type: ignore # Pydantic v1
42
+ from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore # Pydantic v1
43
+ from pydantic.fields import ModelField as ModelField # type: ignore # Pydantic v1
44
+ from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore # Pydantic v1
45
+ from pydantic.typing import get_args as get_args # type: ignore # Pydantic v1
46
+ from pydantic.typing import get_origin as get_origin # type: ignore # Pydantic v1
47
+ from pydantic.typing import is_literal_type as is_literal_type # type: ignore # Pydantic v1
48
+ from pydantic.typing import is_union as is_union # type: ignore # Pydantic v1
49
+
50
+ # isort: on
30
51
 
31
- from .datetime_utils import serialize_datetime
32
- from .serialization import convert_and_respect_annotation_metadata
33
- from typing_extensions import TypeAlias
34
52
 
35
- T = TypeVar("T")
36
- Model = TypeVar("Model", bound=pydantic.BaseModel)
53
+ T = typing.TypeVar("T")
54
+ Model = typing.TypeVar("Model", bound=pydantic.BaseModel)
37
55
 
38
56
 
39
- def parse_obj_as(type_: Type[T], object_: Any) -> T:
57
+ def parse_obj_as(type_: typing.Type[T], object_: typing.Any) -> T:
40
58
  dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
41
59
  if IS_PYDANTIC_V2:
42
- adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined]
60
+ adapter = pydantic.TypeAdapter(type_) # type: ignore # Pydantic v2
43
61
  return adapter.validate_python(dealiased_object)
44
- return pydantic.parse_obj_as(type_, dealiased_object)
62
+ else:
63
+ return pydantic.parse_obj_as(type_, dealiased_object)
45
64
 
46
65
 
47
- def to_jsonable_with_fallback(obj: Any, fallback_serializer: Callable[[Any], Any]) -> Any:
66
+ def to_jsonable_with_fallback(
67
+ obj: typing.Any, fallback_serializer: typing.Callable[[typing.Any], typing.Any]
68
+ ) -> typing.Any:
48
69
  if IS_PYDANTIC_V2:
49
70
  from pydantic_core import to_jsonable_python
50
71
 
51
72
  return to_jsonable_python(obj, fallback=fallback_serializer)
52
- return fallback_serializer(obj)
73
+ else:
74
+ return fallback_serializer(obj)
53
75
 
54
76
 
55
77
  class UniversalBaseModel(pydantic.BaseModel):
56
78
  if IS_PYDANTIC_V2:
57
- model_config: ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( # type: ignore[typeddict-unknown-key]
79
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
58
80
  # Allow fields beginning with `model_` to be used in the model
59
81
  protected_namespaces=(),
60
- )
82
+ ) # type: ignore # Pydantic v2
61
83
 
62
- @pydantic.model_serializer(mode="wrap", when_used="json") # type: ignore[attr-defined]
63
- def serialize_model(self, handler: pydantic.SerializerFunctionWrapHandler) -> Any: # type: ignore[name-defined]
84
+ @pydantic.model_serializer(mode="wrap", when_used="json") # type: ignore # Pydantic v2
85
+ def serialize_model(self, handler: pydantic.SerializerFunctionWrapHandler) -> typing.Any: # type: ignore # Pydantic v2
64
86
  serialized = handler(self)
65
87
  data = {k: serialize_datetime(v) if isinstance(v, dt.datetime) else v for k, v in serialized.items()}
66
88
  return data
@@ -72,28 +94,34 @@ class UniversalBaseModel(pydantic.BaseModel):
72
94
  json_encoders = {dt.datetime: serialize_datetime}
73
95
 
74
96
  @classmethod
75
- def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
97
+ def model_construct(
98
+ cls: typing.Type["Model"], _fields_set: typing.Optional[typing.Set[str]] = None, **values: typing.Any
99
+ ) -> "Model":
76
100
  dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
77
101
  return cls.construct(_fields_set, **dealiased_object)
78
102
 
79
103
  @classmethod
80
- def construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
104
+ def construct(
105
+ cls: typing.Type["Model"], _fields_set: typing.Optional[typing.Set[str]] = None, **values: typing.Any
106
+ ) -> "Model":
81
107
  dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
82
108
  if IS_PYDANTIC_V2:
83
- return super().model_construct(_fields_set, **dealiased_object) # type: ignore[misc]
84
- return super().construct(_fields_set, **dealiased_object)
109
+ return super().model_construct(_fields_set, **dealiased_object) # type: ignore # Pydantic v2
110
+ else:
111
+ return super().construct(_fields_set, **dealiased_object)
85
112
 
86
- def json(self, **kwargs: Any) -> str:
87
- kwargs_with_defaults = {
113
+ def json(self, **kwargs: typing.Any) -> str:
114
+ kwargs_with_defaults: typing.Any = {
88
115
  "by_alias": True,
89
116
  "exclude_unset": True,
90
117
  **kwargs,
91
118
  }
92
119
  if IS_PYDANTIC_V2:
93
- return super().model_dump_json(**kwargs_with_defaults) # type: ignore[misc]
94
- return super().json(**kwargs_with_defaults)
120
+ return super().model_dump_json(**kwargs_with_defaults) # type: ignore # Pydantic v2
121
+ else:
122
+ return super().json(**kwargs_with_defaults)
95
123
 
96
- def dict(self, **kwargs: Any) -> Dict[str, Any]:
124
+ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
97
125
  """
98
126
  Override the default dict method to `exclude_unset` by default. This function patches
99
127
  `exclude_unset` to work include fields within non-None default values.
@@ -104,21 +132,21 @@ class UniversalBaseModel(pydantic.BaseModel):
104
132
  # We'd ideally do the same for Pydantic V2, but it shells out to a library to serialize models
105
133
  # that we have less control over, and this is less intrusive than custom serializers for now.
106
134
  if IS_PYDANTIC_V2:
107
- kwargs_with_defaults_exclude_unset = {
135
+ kwargs_with_defaults_exclude_unset: typing.Any = {
108
136
  **kwargs,
109
137
  "by_alias": True,
110
138
  "exclude_unset": True,
111
139
  "exclude_none": False,
112
140
  }
113
- kwargs_with_defaults_exclude_none = {
141
+ kwargs_with_defaults_exclude_none: typing.Any = {
114
142
  **kwargs,
115
143
  "by_alias": True,
116
144
  "exclude_none": True,
117
145
  "exclude_unset": False,
118
146
  }
119
147
  dict_dump = deep_union_pydantic_dicts(
120
- super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore[misc]
121
- super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore[misc]
148
+ super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore # Pydantic v2
149
+ super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore # Pydantic v2
122
150
  )
123
151
 
124
152
  else:
@@ -138,7 +166,7 @@ class UniversalBaseModel(pydantic.BaseModel):
138
166
  if default is not None:
139
167
  self.__fields_set__.add(name)
140
168
 
141
- kwargs_with_defaults_exclude_unset_include_fields = {
169
+ kwargs_with_defaults_exclude_unset_include_fields: typing.Any = {
142
170
  "by_alias": True,
143
171
  "exclude_unset": True,
144
172
  "include": _fields_set,
@@ -150,10 +178,12 @@ class UniversalBaseModel(pydantic.BaseModel):
150
178
  return convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write")
151
179
 
152
180
 
153
- def _union_list_of_pydantic_dicts(source: List[Any], destination: List[Any]) -> List[Any]:
154
- converted_list: List[Any] = []
181
+ def _union_list_of_pydantic_dicts(
182
+ source: typing.List[typing.Any], destination: typing.List[typing.Any]
183
+ ) -> typing.List[typing.Any]:
184
+ converted_list: typing.List[typing.Any] = []
155
185
  for i, item in enumerate(source):
156
- destination_value = destination[i]
186
+ destination_value = destination[i] # type: ignore
157
187
  if isinstance(item, dict):
158
188
  converted_list.append(deep_union_pydantic_dicts(item, destination_value))
159
189
  elif isinstance(item, list):
@@ -163,7 +193,9 @@ def _union_list_of_pydantic_dicts(source: List[Any], destination: List[Any]) ->
163
193
  return converted_list
164
194
 
165
195
 
166
- def deep_union_pydantic_dicts(source: Dict[str, Any], destination: Dict[str, Any]) -> Dict[str, Any]:
196
+ def deep_union_pydantic_dicts(
197
+ source: typing.Dict[str, typing.Any], destination: typing.Dict[str, typing.Any]
198
+ ) -> typing.Dict[str, typing.Any]:
167
199
  for key, value in source.items():
168
200
  node = destination.setdefault(key, {})
169
201
  if isinstance(value, dict):
@@ -181,16 +213,18 @@ def deep_union_pydantic_dicts(source: Dict[str, Any], destination: Dict[str, Any
181
213
 
182
214
  if IS_PYDANTIC_V2:
183
215
 
184
- class V2RootModel(UniversalBaseModel, pydantic.RootModel): # type: ignore[misc, name-defined, type-arg]
216
+ class V2RootModel(UniversalBaseModel, pydantic.RootModel): # type: ignore # Pydantic v2
185
217
  pass
186
218
 
187
- UniversalRootModel: TypeAlias = V2RootModel # type: ignore[misc]
219
+ UniversalRootModel: typing_extensions.TypeAlias = V2RootModel # type: ignore
188
220
  else:
189
- UniversalRootModel: TypeAlias = UniversalBaseModel # type: ignore[misc, no-redef]
221
+ UniversalRootModel: typing_extensions.TypeAlias = UniversalBaseModel # type: ignore
190
222
 
191
223
 
192
- def encode_by_type(o: Any) -> Any:
193
- encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(tuple)
224
+ def encode_by_type(o: typing.Any) -> typing.Any:
225
+ encoders_by_class_tuples: typing.Dict[typing.Callable[[typing.Any], typing.Any], typing.Tuple[typing.Any, ...]] = (
226
+ defaultdict(tuple)
227
+ )
194
228
  for type_, encoder in encoders_by_type.items():
195
229
  encoders_by_class_tuples[encoder] += (type_,)
196
230
 
@@ -201,49 +235,54 @@ def encode_by_type(o: Any) -> Any:
201
235
  return encoder(o)
202
236
 
203
237
 
204
- def update_forward_refs(model: Type["Model"], **localns: Any) -> None:
238
+ def update_forward_refs(model: typing.Type["Model"], **localns: typing.Any) -> None:
205
239
  if IS_PYDANTIC_V2:
206
- model.model_rebuild(raise_errors=False) # type: ignore[attr-defined]
240
+ model.model_rebuild(raise_errors=False) # type: ignore # Pydantic v2
207
241
  else:
208
242
  model.update_forward_refs(**localns)
209
243
 
210
244
 
211
245
  # Mirrors Pydantic's internal typing
212
- AnyCallable = Callable[..., Any]
246
+ AnyCallable = typing.Callable[..., typing.Any]
213
247
 
214
248
 
215
249
  def universal_root_validator(
216
250
  pre: bool = False,
217
- ) -> Callable[[AnyCallable], AnyCallable]:
251
+ ) -> typing.Callable[[AnyCallable], AnyCallable]:
218
252
  def decorator(func: AnyCallable) -> AnyCallable:
219
253
  if IS_PYDANTIC_V2:
220
- return cast(AnyCallable, pydantic.model_validator(mode="before" if pre else "after")(func)) # type: ignore[attr-defined]
221
- return cast(AnyCallable, pydantic.root_validator(pre=pre)(func)) # type: ignore[call-overload]
254
+ return pydantic.model_validator(mode="before" if pre else "after")(func) # type: ignore # Pydantic v2
255
+ else:
256
+ return pydantic.root_validator(pre=pre)(func) # type: ignore # Pydantic v1
222
257
 
223
258
  return decorator
224
259
 
225
260
 
226
- def universal_field_validator(field_name: str, pre: bool = False) -> Callable[[AnyCallable], AnyCallable]:
261
+ def universal_field_validator(field_name: str, pre: bool = False) -> typing.Callable[[AnyCallable], AnyCallable]:
227
262
  def decorator(func: AnyCallable) -> AnyCallable:
228
263
  if IS_PYDANTIC_V2:
229
- return cast(AnyCallable, pydantic.field_validator(field_name, mode="before" if pre else "after")(func)) # type: ignore[attr-defined]
230
- return cast(AnyCallable, pydantic.validator(field_name, pre=pre)(func))
264
+ return pydantic.field_validator(field_name, mode="before" if pre else "after")(func) # type: ignore # Pydantic v2
265
+ else:
266
+ return pydantic.validator(field_name, pre=pre)(func) # type: ignore # Pydantic v1
231
267
 
232
268
  return decorator
233
269
 
234
270
 
235
- PydanticField = Union[ModelField, pydantic.fields.FieldInfo]
271
+ PydanticField = typing.Union[ModelField, pydantic.fields.FieldInfo]
236
272
 
237
273
 
238
- def _get_model_fields(model: Type["Model"]) -> Mapping[str, PydanticField]:
274
+ def _get_model_fields(
275
+ model: typing.Type["Model"],
276
+ ) -> typing.Mapping[str, PydanticField]:
239
277
  if IS_PYDANTIC_V2:
240
- return cast(Mapping[str, PydanticField], model.model_fields) # type: ignore[attr-defined]
241
- return cast(Mapping[str, PydanticField], model.__fields__)
278
+ return model.model_fields # type: ignore # Pydantic v2
279
+ else:
280
+ return model.__fields__ # type: ignore # Pydantic v1
242
281
 
243
282
 
244
- def _get_field_default(field: PydanticField) -> Any:
283
+ def _get_field_default(field: PydanticField) -> typing.Any:
245
284
  try:
246
- value = field.get_default() # type: ignore[union-attr]
285
+ value = field.get_default() # type: ignore # Pydantic < v1.10.15
247
286
  except:
248
287
  value = field.default
249
288
  if IS_PYDANTIC_V2:
sarvamai/environment.py CHANGED
@@ -1,14 +1,7 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
- from __future__ import annotations
3
+ import enum
4
4
 
5
5
 
6
- class SarvamAIEnvironment:
7
- PRODUCTION: SarvamAIEnvironment
8
-
9
- def __init__(self, *, base: str, production: str):
10
- self.base = base
11
- self.production = production
12
-
13
-
14
- SarvamAIEnvironment.PRODUCTION = SarvamAIEnvironment(base="https://api.sarvam.ai", production="wss://api.sarvam.ai")
6
+ class SarvamAIEnvironment(enum.Enum):
7
+ PRODUCTION = "https://api.sarvam.ai"
@@ -1,7 +1,5 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
- # isort: skip_file
4
-
5
3
  from .bad_request_error import BadRequestError
6
4
  from .forbidden_error import ForbiddenError
7
5
  from .internal_server_error import InternalServerError
@@ -1,10 +1,9 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
- import typing
4
-
5
3
  from ..core.api_error import ApiError
4
+ import typing
6
5
 
7
6
 
8
7
  class BadRequestError(ApiError):
9
- def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
10
- super().__init__(status_code=400, headers=headers, body=body)
8
+ def __init__(self, body: typing.Optional[typing.Any]):
9
+ super().__init__(status_code=400, body=body)
@@ -1,10 +1,9 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
- import typing
4
-
5
3
  from ..core.api_error import ApiError
4
+ import typing
6
5
 
7
6
 
8
7
  class ForbiddenError(ApiError):
9
- def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
10
- super().__init__(status_code=403, headers=headers, body=body)
8
+ def __init__(self, body: typing.Optional[typing.Any]):
9
+ super().__init__(status_code=403, body=body)
@@ -1,10 +1,9 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
- import typing
4
-
5
3
  from ..core.api_error import ApiError
4
+ import typing
6
5
 
7
6
 
8
7
  class InternalServerError(ApiError):
9
- def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
10
- super().__init__(status_code=500, headers=headers, body=body)
8
+ def __init__(self, body: typing.Optional[typing.Any]):
9
+ super().__init__(status_code=500, body=body)
@@ -1,11 +1,9 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
- import typing
4
-
5
3
  from ..core.api_error import ApiError
6
4
  from ..types.error_message import ErrorMessage
7
5
 
8
6
 
9
7
  class ServiceUnavailableError(ApiError):
10
- def __init__(self, body: ErrorMessage, headers: typing.Optional[typing.Dict[str, str]] = None):
11
- super().__init__(status_code=503, headers=headers, body=body)
8
+ def __init__(self, body: ErrorMessage):
9
+ super().__init__(status_code=503, body=body)