mistralai 1.9.11__py3-none-any.whl → 1.10.1__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 (151) hide show
  1. mistralai/_hooks/registration.py +5 -0
  2. mistralai/_hooks/tracing.py +75 -0
  3. mistralai/_version.py +2 -2
  4. mistralai/accesses.py +8 -8
  5. mistralai/agents.py +29 -17
  6. mistralai/chat.py +41 -29
  7. mistralai/classifiers.py +13 -1
  8. mistralai/conversations.py +294 -62
  9. mistralai/documents.py +19 -3
  10. mistralai/embeddings.py +13 -7
  11. mistralai/extra/README.md +1 -1
  12. mistralai/extra/mcp/auth.py +10 -11
  13. mistralai/extra/mcp/base.py +17 -16
  14. mistralai/extra/mcp/sse.py +13 -15
  15. mistralai/extra/mcp/stdio.py +5 -6
  16. mistralai/extra/observability/__init__.py +15 -0
  17. mistralai/extra/observability/otel.py +372 -0
  18. mistralai/extra/run/context.py +33 -43
  19. mistralai/extra/run/result.py +29 -30
  20. mistralai/extra/run/tools.py +34 -23
  21. mistralai/extra/struct_chat.py +15 -8
  22. mistralai/extra/utils/response_format.py +5 -3
  23. mistralai/files.py +6 -0
  24. mistralai/fim.py +17 -5
  25. mistralai/mistral_agents.py +229 -1
  26. mistralai/mistral_jobs.py +39 -13
  27. mistralai/models/__init__.py +99 -3
  28. mistralai/models/agent.py +15 -2
  29. mistralai/models/agentconversation.py +11 -3
  30. mistralai/models/agentcreationrequest.py +6 -2
  31. mistralai/models/agents_api_v1_agents_deleteop.py +16 -0
  32. mistralai/models/agents_api_v1_agents_getop.py +40 -3
  33. mistralai/models/agents_api_v1_agents_listop.py +72 -2
  34. mistralai/models/agents_api_v1_conversations_deleteop.py +18 -0
  35. mistralai/models/agents_api_v1_conversations_listop.py +39 -2
  36. mistralai/models/agentscompletionrequest.py +21 -6
  37. mistralai/models/agentscompletionstreamrequest.py +21 -6
  38. mistralai/models/agentupdaterequest.py +18 -2
  39. mistralai/models/audioencoding.py +13 -0
  40. mistralai/models/audioformat.py +19 -0
  41. mistralai/models/audiotranscriptionrequest.py +2 -0
  42. mistralai/models/batchjobin.py +26 -5
  43. mistralai/models/batchjobout.py +5 -0
  44. mistralai/models/batchrequest.py +48 -0
  45. mistralai/models/chatcompletionrequest.py +22 -5
  46. mistralai/models/chatcompletionstreamrequest.py +22 -5
  47. mistralai/models/classificationrequest.py +37 -3
  48. mistralai/models/conversationrequest.py +15 -4
  49. mistralai/models/conversationrestartrequest.py +50 -2
  50. mistralai/models/conversationrestartstreamrequest.py +50 -2
  51. mistralai/models/conversationstreamrequest.py +15 -4
  52. mistralai/models/documentout.py +26 -10
  53. mistralai/models/documentupdatein.py +24 -3
  54. mistralai/models/embeddingrequest.py +19 -11
  55. mistralai/models/files_api_routes_list_filesop.py +7 -0
  56. mistralai/models/fimcompletionrequest.py +8 -9
  57. mistralai/models/fimcompletionstreamrequest.py +8 -9
  58. mistralai/models/jobs_api_routes_batch_get_batch_jobop.py +40 -3
  59. mistralai/models/libraries_documents_list_v1op.py +15 -2
  60. mistralai/models/libraryout.py +10 -7
  61. mistralai/models/listfilesout.py +35 -4
  62. mistralai/models/modelcapabilities.py +13 -4
  63. mistralai/models/modelconversation.py +8 -2
  64. mistralai/models/ocrpageobject.py +26 -5
  65. mistralai/models/ocrrequest.py +17 -1
  66. mistralai/models/ocrtableobject.py +31 -0
  67. mistralai/models/prediction.py +4 -0
  68. mistralai/models/requestsource.py +7 -0
  69. mistralai/models/responseformat.py +4 -2
  70. mistralai/models/responseformats.py +0 -1
  71. mistralai/models/sharingdelete.py +36 -5
  72. mistralai/models/sharingin.py +36 -5
  73. mistralai/models/sharingout.py +3 -3
  74. mistralai/models/toolexecutiondeltaevent.py +13 -4
  75. mistralai/models/toolexecutiondoneevent.py +13 -4
  76. mistralai/models/toolexecutionentry.py +9 -4
  77. mistralai/models/toolexecutionstartedevent.py +13 -4
  78. mistralai/models/toolfilechunk.py +11 -4
  79. mistralai/models/toolreferencechunk.py +13 -4
  80. mistralai/models_.py +2 -14
  81. mistralai/ocr.py +18 -0
  82. mistralai/transcriptions.py +4 -4
  83. {mistralai-1.9.11.dist-info → mistralai-1.10.1.dist-info}/METADATA +162 -152
  84. {mistralai-1.9.11.dist-info → mistralai-1.10.1.dist-info}/RECORD +168 -144
  85. {mistralai-1.9.11.dist-info → mistralai-1.10.1.dist-info}/WHEEL +1 -1
  86. mistralai_azure/_version.py +3 -3
  87. mistralai_azure/basesdk.py +15 -5
  88. mistralai_azure/chat.py +59 -98
  89. mistralai_azure/models/__init__.py +50 -3
  90. mistralai_azure/models/chatcompletionrequest.py +16 -4
  91. mistralai_azure/models/chatcompletionstreamrequest.py +16 -4
  92. mistralai_azure/models/httpvalidationerror.py +11 -6
  93. mistralai_azure/models/mistralazureerror.py +26 -0
  94. mistralai_azure/models/no_response_error.py +13 -0
  95. mistralai_azure/models/prediction.py +4 -0
  96. mistralai_azure/models/responseformat.py +4 -2
  97. mistralai_azure/models/responseformats.py +0 -1
  98. mistralai_azure/models/responsevalidationerror.py +25 -0
  99. mistralai_azure/models/sdkerror.py +30 -14
  100. mistralai_azure/models/systemmessage.py +7 -3
  101. mistralai_azure/models/systemmessagecontentchunks.py +21 -0
  102. mistralai_azure/models/thinkchunk.py +35 -0
  103. mistralai_azure/ocr.py +15 -36
  104. mistralai_azure/utils/__init__.py +18 -5
  105. mistralai_azure/utils/eventstreaming.py +10 -0
  106. mistralai_azure/utils/serializers.py +3 -2
  107. mistralai_azure/utils/unmarshal_json_response.py +24 -0
  108. mistralai_gcp/_hooks/types.py +7 -0
  109. mistralai_gcp/_version.py +4 -4
  110. mistralai_gcp/basesdk.py +27 -25
  111. mistralai_gcp/chat.py +75 -98
  112. mistralai_gcp/fim.py +39 -74
  113. mistralai_gcp/httpclient.py +6 -16
  114. mistralai_gcp/models/__init__.py +321 -116
  115. mistralai_gcp/models/assistantmessage.py +1 -1
  116. mistralai_gcp/models/chatcompletionrequest.py +36 -7
  117. mistralai_gcp/models/chatcompletionresponse.py +6 -6
  118. mistralai_gcp/models/chatcompletionstreamrequest.py +36 -7
  119. mistralai_gcp/models/completionresponsestreamchoice.py +1 -1
  120. mistralai_gcp/models/deltamessage.py +1 -1
  121. mistralai_gcp/models/fimcompletionrequest.py +3 -9
  122. mistralai_gcp/models/fimcompletionresponse.py +6 -6
  123. mistralai_gcp/models/fimcompletionstreamrequest.py +3 -9
  124. mistralai_gcp/models/httpvalidationerror.py +11 -6
  125. mistralai_gcp/models/imageurl.py +1 -1
  126. mistralai_gcp/models/jsonschema.py +1 -1
  127. mistralai_gcp/models/mistralgcperror.py +26 -0
  128. mistralai_gcp/models/mistralpromptmode.py +8 -0
  129. mistralai_gcp/models/no_response_error.py +13 -0
  130. mistralai_gcp/models/prediction.py +4 -0
  131. mistralai_gcp/models/responseformat.py +5 -3
  132. mistralai_gcp/models/responseformats.py +0 -1
  133. mistralai_gcp/models/responsevalidationerror.py +25 -0
  134. mistralai_gcp/models/sdkerror.py +30 -14
  135. mistralai_gcp/models/systemmessage.py +7 -3
  136. mistralai_gcp/models/systemmessagecontentchunks.py +21 -0
  137. mistralai_gcp/models/thinkchunk.py +35 -0
  138. mistralai_gcp/models/toolmessage.py +1 -1
  139. mistralai_gcp/models/usageinfo.py +71 -8
  140. mistralai_gcp/models/usermessage.py +1 -1
  141. mistralai_gcp/sdk.py +12 -10
  142. mistralai_gcp/sdkconfiguration.py +0 -7
  143. mistralai_gcp/types/basemodel.py +3 -3
  144. mistralai_gcp/utils/__init__.py +143 -45
  145. mistralai_gcp/utils/datetimes.py +23 -0
  146. mistralai_gcp/utils/enums.py +67 -27
  147. mistralai_gcp/utils/eventstreaming.py +10 -0
  148. mistralai_gcp/utils/forms.py +49 -28
  149. mistralai_gcp/utils/serializers.py +33 -3
  150. mistralai_gcp/utils/unmarshal_json_response.py +24 -0
  151. {mistralai-1.9.11.dist-info → mistralai-1.10.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,19 +1,82 @@
1
1
  """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
2
 
3
3
  from __future__ import annotations
4
- from mistralai_gcp.types import BaseModel
5
- from typing_extensions import TypedDict
4
+ from mistralai_gcp.types import (
5
+ BaseModel,
6
+ Nullable,
7
+ OptionalNullable,
8
+ UNSET,
9
+ UNSET_SENTINEL,
10
+ )
11
+ import pydantic
12
+ from pydantic import ConfigDict, model_serializer
13
+ from typing import Any, Dict, Optional
14
+ from typing_extensions import NotRequired, TypedDict
6
15
 
7
16
 
8
17
  class UsageInfoTypedDict(TypedDict):
9
- prompt_tokens: int
10
- completion_tokens: int
11
- total_tokens: int
18
+ prompt_tokens: NotRequired[int]
19
+ completion_tokens: NotRequired[int]
20
+ total_tokens: NotRequired[int]
21
+ prompt_audio_seconds: NotRequired[Nullable[int]]
12
22
 
13
23
 
14
24
  class UsageInfo(BaseModel):
15
- prompt_tokens: int
25
+ model_config = ConfigDict(
26
+ populate_by_name=True, arbitrary_types_allowed=True, extra="allow"
27
+ )
28
+ __pydantic_extra__: Dict[str, Any] = pydantic.Field(init=False)
16
29
 
17
- completion_tokens: int
30
+ prompt_tokens: Optional[int] = 0
18
31
 
19
- total_tokens: int
32
+ completion_tokens: Optional[int] = 0
33
+
34
+ total_tokens: Optional[int] = 0
35
+
36
+ prompt_audio_seconds: OptionalNullable[int] = UNSET
37
+
38
+ @property
39
+ def additional_properties(self):
40
+ return self.__pydantic_extra__
41
+
42
+ @additional_properties.setter
43
+ def additional_properties(self, value):
44
+ self.__pydantic_extra__ = value # pyright: ignore[reportIncompatibleVariableOverride]
45
+
46
+ @model_serializer(mode="wrap")
47
+ def serialize_model(self, handler):
48
+ optional_fields = [
49
+ "prompt_tokens",
50
+ "completion_tokens",
51
+ "total_tokens",
52
+ "prompt_audio_seconds",
53
+ ]
54
+ nullable_fields = ["prompt_audio_seconds"]
55
+ null_default_fields = []
56
+
57
+ serialized = handler(self)
58
+
59
+ m = {}
60
+
61
+ for n, f in type(self).model_fields.items():
62
+ k = f.alias or n
63
+ val = serialized.get(k)
64
+ serialized.pop(k, None)
65
+
66
+ optional_nullable = k in optional_fields and k in nullable_fields
67
+ is_set = (
68
+ self.__pydantic_fields_set__.intersection({n})
69
+ or k in null_default_fields
70
+ ) # pylint: disable=no-member
71
+
72
+ if val is not None and val != UNSET_SENTINEL:
73
+ m[k] = val
74
+ elif val != UNSET_SENTINEL and (
75
+ not k in optional_fields or (optional_nullable and is_set)
76
+ ):
77
+ m[k] = val
78
+
79
+ for k, v in serialized.items():
80
+ m[k] = v
81
+
82
+ return m
@@ -39,7 +39,7 @@ class UserMessage(BaseModel):
39
39
 
40
40
  m = {}
41
41
 
42
- for n, f in self.model_fields.items():
42
+ for n, f in type(self).model_fields.items():
43
43
  k = f.alias or n
44
44
  val = serialized.get(k)
45
45
  serialized.pop(k, None)
mistralai_gcp/sdk.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import json
4
4
  import weakref
5
- from typing import Any, Optional, cast
5
+ from typing import Any, Optional, Union, cast
6
6
 
7
7
  import google.auth
8
8
  import google.auth.credentials
@@ -67,30 +67,32 @@ class MistralGoogleCloud(BaseSDK):
67
67
  :param timeout_ms: Optional request timeout applied to each operation in milliseconds
68
68
  """
69
69
 
70
+ credentials = None
70
71
  if not access_token:
71
72
  credentials, loaded_project_id = google.auth.default(
72
73
  scopes=["https://www.googleapis.com/auth/cloud-platform"],
73
74
  )
74
- credentials.refresh(google.auth.transport.requests.Request())
75
75
 
76
- if not isinstance(credentials, google.auth.credentials.Credentials):
77
- raise models.SDKError(
78
- "credentials must be an instance of google.auth.credentials.Credentials"
79
- )
76
+ # default will already raise a google.auth.exceptions.DefaultCredentialsError if no credentials are found
77
+ assert isinstance(
78
+ credentials, google.auth.credentials.Credentials
79
+ ), "credentials must be an instance of google.auth.credentials.Credentials"
80
80
 
81
+ credentials.refresh(google.auth.transport.requests.Request())
81
82
  project_id = project_id or loaded_project_id
82
83
 
83
84
  if project_id is None:
84
- raise models.SDKError("project_id must be provided")
85
+ raise ValueError("project_id must be provided")
85
86
 
86
87
  def auth_token() -> str:
87
88
  if access_token:
88
89
  return access_token
89
90
 
91
+ assert credentials is not None, "credentials must be initialized"
90
92
  credentials.refresh(google.auth.transport.requests.Request())
91
93
  token = credentials.token
92
94
  if not token:
93
- raise models.SDKError("Failed to get token from credentials")
95
+ raise Exception("Failed to get token from credentials")
94
96
  return token
95
97
 
96
98
  client_supplied = True
@@ -197,7 +199,7 @@ class GoogleCloudBeforeRequestHook(BeforeRequestHook):
197
199
 
198
200
  def before_request(
199
201
  self, hook_ctx, request: httpx.Request
200
- ) -> httpx.Request | Exception:
202
+ ) -> Union[httpx.Request, Exception]:
201
203
  # The goal of this function is to template in the region, project and model into the URL path
202
204
  # We do this here so that the API remains more user-friendly
203
205
  model_id = None
@@ -210,7 +212,7 @@ class GoogleCloudBeforeRequestHook(BeforeRequestHook):
210
212
  new_content = json.dumps(parsed).encode("utf-8")
211
213
 
212
214
  if model_id == "":
213
- raise models.SDKError("model must be provided")
215
+ raise ValueError("model must be provided")
214
216
 
215
217
  stream = "streamRawPredict" in request.url.path
216
218
  specifier = "streamRawPredict" if stream else "rawPredict"
@@ -1,6 +1,5 @@
1
1
  """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
2
 
3
- from ._hooks import SDKHooks
4
3
  from ._version import (
5
4
  __gen_version__,
6
5
  __openapi_doc_version__,
@@ -42,9 +41,6 @@ class SDKConfiguration:
42
41
  retry_config: OptionalNullable[RetryConfig] = Field(default_factory=lambda: UNSET)
43
42
  timeout_ms: Optional[int] = None
44
43
 
45
- def __post_init__(self):
46
- self._hooks = SDKHooks()
47
-
48
44
  def get_server_details(self) -> Tuple[str, Dict[str, str]]:
49
45
  if self.server_url is not None and self.server_url:
50
46
  return remove_suffix(self.server_url, "/"), {}
@@ -55,6 +51,3 @@ class SDKConfiguration:
55
51
  raise ValueError(f'Invalid server "{self.server}"')
56
52
 
57
53
  return SERVERS[self.server], {}
58
-
59
- def get_hooks(self) -> SDKHooks:
60
- return self._hooks
@@ -2,7 +2,7 @@
2
2
 
3
3
  from pydantic import ConfigDict, model_serializer
4
4
  from pydantic import BaseModel as PydanticBaseModel
5
- from typing import TYPE_CHECKING, Literal, Optional, TypeVar, Union, NewType
5
+ from typing import TYPE_CHECKING, Literal, Optional, TypeVar, Union
6
6
  from typing_extensions import TypeAliasType, TypeAlias
7
7
 
8
8
 
@@ -35,5 +35,5 @@ else:
35
35
  "OptionalNullable", Union[Optional[Nullable[T]], Unset], type_params=(T,)
36
36
  )
37
37
 
38
- UnrecognizedInt = NewType("UnrecognizedInt", int)
39
- UnrecognizedStr = NewType("UnrecognizedStr", str)
38
+ UnrecognizedInt: TypeAlias = int
39
+ UnrecognizedStr: TypeAlias = str
@@ -1,50 +1,57 @@
1
1
  """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
2
 
3
- from .annotations import get_discriminator
4
- from .enums import OpenEnumMeta
5
- from .headers import get_headers, get_response_headers
6
- from .metadata import (
7
- FieldMetadata,
8
- find_metadata,
9
- FormMetadata,
10
- HeaderMetadata,
11
- MultipartFormMetadata,
12
- PathParamMetadata,
13
- QueryParamMetadata,
14
- RequestMetadata,
15
- SecurityMetadata,
16
- )
17
- from .queryparams import get_query_params
18
- from .retries import BackoffStrategy, Retries, retry, retry_async, RetryConfig
19
- from .requestbodies import serialize_request_body, SerializedRequestBody
20
- from .security import get_security
21
- from .serializers import (
22
- get_pydantic_model,
23
- marshal_json,
24
- unmarshal,
25
- unmarshal_json,
26
- serialize_decimal,
27
- serialize_float,
28
- serialize_int,
29
- stream_to_text,
30
- stream_to_text_async,
31
- stream_to_bytes,
32
- stream_to_bytes_async,
33
- validate_const,
34
- validate_decimal,
35
- validate_float,
36
- validate_int,
37
- validate_open_enum,
38
- )
39
- from .url import generate_url, template_url, remove_suffix
40
- from .values import (
41
- get_global_from_env,
42
- match_content_type,
43
- match_status_codes,
44
- match_response,
45
- cast_partial,
46
- )
47
- from .logger import Logger, get_body_content, get_default_logger
3
+ from typing import TYPE_CHECKING
4
+ from importlib import import_module
5
+ import builtins
6
+ import sys
7
+
8
+ if TYPE_CHECKING:
9
+ from .annotations import get_discriminator
10
+ from .datetimes import parse_datetime
11
+ from .enums import OpenEnumMeta
12
+ from .headers import get_headers, get_response_headers
13
+ from .metadata import (
14
+ FieldMetadata,
15
+ find_metadata,
16
+ FormMetadata,
17
+ HeaderMetadata,
18
+ MultipartFormMetadata,
19
+ PathParamMetadata,
20
+ QueryParamMetadata,
21
+ RequestMetadata,
22
+ SecurityMetadata,
23
+ )
24
+ from .queryparams import get_query_params
25
+ from .retries import BackoffStrategy, Retries, retry, retry_async, RetryConfig
26
+ from .requestbodies import serialize_request_body, SerializedRequestBody
27
+ from .security import get_security
28
+ from .serializers import (
29
+ get_pydantic_model,
30
+ marshal_json,
31
+ unmarshal,
32
+ unmarshal_json,
33
+ serialize_decimal,
34
+ serialize_float,
35
+ serialize_int,
36
+ stream_to_text,
37
+ stream_to_text_async,
38
+ stream_to_bytes,
39
+ stream_to_bytes_async,
40
+ validate_const,
41
+ validate_decimal,
42
+ validate_float,
43
+ validate_int,
44
+ validate_open_enum,
45
+ )
46
+ from .url import generate_url, template_url, remove_suffix
47
+ from .values import (
48
+ get_global_from_env,
49
+ match_content_type,
50
+ match_status_codes,
51
+ match_response,
52
+ cast_partial,
53
+ )
54
+ from .logger import Logger, get_body_content, get_default_logger
48
55
 
49
56
  __all__ = [
50
57
  "BackoffStrategy",
@@ -55,6 +62,7 @@ __all__ = [
55
62
  "get_body_content",
56
63
  "get_default_logger",
57
64
  "get_discriminator",
65
+ "parse_datetime",
58
66
  "get_global_from_env",
59
67
  "get_headers",
60
68
  "get_pydantic_model",
@@ -97,3 +105,93 @@ __all__ = [
97
105
  "validate_open_enum",
98
106
  "cast_partial",
99
107
  ]
108
+
109
+ _dynamic_imports: dict[str, str] = {
110
+ "BackoffStrategy": ".retries",
111
+ "FieldMetadata": ".metadata",
112
+ "find_metadata": ".metadata",
113
+ "FormMetadata": ".metadata",
114
+ "generate_url": ".url",
115
+ "get_body_content": ".logger",
116
+ "get_default_logger": ".logger",
117
+ "get_discriminator": ".annotations",
118
+ "parse_datetime": ".datetimes",
119
+ "get_global_from_env": ".values",
120
+ "get_headers": ".headers",
121
+ "get_pydantic_model": ".serializers",
122
+ "get_query_params": ".queryparams",
123
+ "get_response_headers": ".headers",
124
+ "get_security": ".security",
125
+ "HeaderMetadata": ".metadata",
126
+ "Logger": ".logger",
127
+ "marshal_json": ".serializers",
128
+ "match_content_type": ".values",
129
+ "match_status_codes": ".values",
130
+ "match_response": ".values",
131
+ "MultipartFormMetadata": ".metadata",
132
+ "OpenEnumMeta": ".enums",
133
+ "PathParamMetadata": ".metadata",
134
+ "QueryParamMetadata": ".metadata",
135
+ "remove_suffix": ".url",
136
+ "Retries": ".retries",
137
+ "retry": ".retries",
138
+ "retry_async": ".retries",
139
+ "RetryConfig": ".retries",
140
+ "RequestMetadata": ".metadata",
141
+ "SecurityMetadata": ".metadata",
142
+ "serialize_decimal": ".serializers",
143
+ "serialize_float": ".serializers",
144
+ "serialize_int": ".serializers",
145
+ "serialize_request_body": ".requestbodies",
146
+ "SerializedRequestBody": ".requestbodies",
147
+ "stream_to_text": ".serializers",
148
+ "stream_to_text_async": ".serializers",
149
+ "stream_to_bytes": ".serializers",
150
+ "stream_to_bytes_async": ".serializers",
151
+ "template_url": ".url",
152
+ "unmarshal": ".serializers",
153
+ "unmarshal_json": ".serializers",
154
+ "validate_decimal": ".serializers",
155
+ "validate_const": ".serializers",
156
+ "validate_float": ".serializers",
157
+ "validate_int": ".serializers",
158
+ "validate_open_enum": ".serializers",
159
+ "cast_partial": ".values",
160
+ }
161
+
162
+
163
+ def dynamic_import(modname, retries=3):
164
+ for attempt in range(retries):
165
+ try:
166
+ return import_module(modname, __package__)
167
+ except KeyError:
168
+ # Clear any half-initialized module and retry
169
+ sys.modules.pop(modname, None)
170
+ if attempt == retries - 1:
171
+ break
172
+ raise KeyError(f"Failed to import module '{modname}' after {retries} attempts")
173
+
174
+
175
+ def __getattr__(attr_name: str) -> object:
176
+ module_name = _dynamic_imports.get(attr_name)
177
+ if module_name is None:
178
+ raise AttributeError(
179
+ f"no {attr_name} found in _dynamic_imports, module name -> {__name__} "
180
+ )
181
+
182
+ try:
183
+ module = dynamic_import(module_name)
184
+ return getattr(module, attr_name)
185
+ except ImportError as e:
186
+ raise ImportError(
187
+ f"Failed to import {attr_name} from {module_name}: {e}"
188
+ ) from e
189
+ except AttributeError as e:
190
+ raise AttributeError(
191
+ f"Failed to get {attr_name} from {module_name}: {e}"
192
+ ) from e
193
+
194
+
195
+ def __dir__():
196
+ lazy_attrs = builtins.list(_dynamic_imports.keys())
197
+ return builtins.sorted(lazy_attrs)
@@ -0,0 +1,23 @@
1
+ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
+
3
+ from datetime import datetime
4
+ import sys
5
+
6
+
7
+ def parse_datetime(datetime_string: str) -> datetime:
8
+ """
9
+ Convert a RFC 3339 / ISO 8601 formatted string into a datetime object.
10
+ Python versions 3.11 and later support parsing RFC 3339 directly with
11
+ datetime.fromisoformat(), but for earlier versions, this function
12
+ encapsulates the necessary extra logic.
13
+ """
14
+ # Python 3.11 and later can parse RFC 3339 directly
15
+ if sys.version_info >= (3, 11):
16
+ return datetime.fromisoformat(datetime_string)
17
+
18
+ # For Python 3.10 and earlier, a common ValueError is trailing 'Z' suffix,
19
+ # so fix that upfront.
20
+ if datetime_string.endswith("Z"):
21
+ datetime_string = datetime_string[:-1] + "+00:00"
22
+
23
+ return datetime.fromisoformat(datetime_string)
@@ -1,34 +1,74 @@
1
1
  """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
2
 
3
3
  import enum
4
-
4
+ import sys
5
5
 
6
6
  class OpenEnumMeta(enum.EnumMeta):
7
- def __call__(
8
- cls, value, names=None, *, module=None, qualname=None, type=None, start=1
9
- ):
10
- # The `type` kwarg also happens to be a built-in that pylint flags as
11
- # redeclared. Safe to ignore this lint rule with this scope.
12
- # pylint: disable=redefined-builtin
7
+ # The __call__ method `boundary` kwarg was added in 3.11 and must be present
8
+ # for pyright. Refer also: https://github.com/pylint-dev/pylint/issues/9622
9
+ # pylint: disable=unexpected-keyword-arg
10
+ # The __call__ method `values` varg must be named for pyright.
11
+ # pylint: disable=keyword-arg-before-vararg
12
+
13
+ if sys.version_info >= (3, 11):
14
+ def __call__(
15
+ cls, value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None
16
+ ):
17
+ # The `type` kwarg also happens to be a built-in that pylint flags as
18
+ # redeclared. Safe to ignore this lint rule with this scope.
19
+ # pylint: disable=redefined-builtin
20
+
21
+ if names is not None:
22
+ return super().__call__(
23
+ value,
24
+ names=names,
25
+ *values,
26
+ module=module,
27
+ qualname=qualname,
28
+ type=type,
29
+ start=start,
30
+ boundary=boundary,
31
+ )
32
+
33
+ try:
34
+ return super().__call__(
35
+ value,
36
+ names=names, # pyright: ignore[reportArgumentType]
37
+ *values,
38
+ module=module,
39
+ qualname=qualname,
40
+ type=type,
41
+ start=start,
42
+ boundary=boundary,
43
+ )
44
+ except ValueError:
45
+ return value
46
+ else:
47
+ def __call__(
48
+ cls, value, names=None, *, module=None, qualname=None, type=None, start=1
49
+ ):
50
+ # The `type` kwarg also happens to be a built-in that pylint flags as
51
+ # redeclared. Safe to ignore this lint rule with this scope.
52
+ # pylint: disable=redefined-builtin
13
53
 
14
- if names is not None:
15
- return super().__call__(
16
- value,
17
- names=names,
18
- module=module,
19
- qualname=qualname,
20
- type=type,
21
- start=start,
22
- )
54
+ if names is not None:
55
+ return super().__call__(
56
+ value,
57
+ names=names,
58
+ module=module,
59
+ qualname=qualname,
60
+ type=type,
61
+ start=start,
62
+ )
23
63
 
24
- try:
25
- return super().__call__(
26
- value,
27
- names=names, # pyright: ignore[reportArgumentType]
28
- module=module,
29
- qualname=qualname,
30
- type=type,
31
- start=start,
32
- )
33
- except ValueError:
34
- return value
64
+ try:
65
+ return super().__call__(
66
+ value,
67
+ names=names, # pyright: ignore[reportArgumentType]
68
+ module=module,
69
+ qualname=qualname,
70
+ type=type,
71
+ start=start,
72
+ )
73
+ except ValueError:
74
+ return value
@@ -17,6 +17,9 @@ T = TypeVar("T")
17
17
 
18
18
 
19
19
  class EventStream(Generic[T]):
20
+ # Holds a reference to the SDK client to avoid it being garbage collected
21
+ # and cause termination of the underlying httpx client.
22
+ client_ref: Optional[object]
20
23
  response: httpx.Response
21
24
  generator: Generator[T, None, None]
22
25
 
@@ -25,9 +28,11 @@ class EventStream(Generic[T]):
25
28
  response: httpx.Response,
26
29
  decoder: Callable[[str], T],
27
30
  sentinel: Optional[str] = None,
31
+ client_ref: Optional[object] = None,
28
32
  ):
29
33
  self.response = response
30
34
  self.generator = stream_events(response, decoder, sentinel)
35
+ self.client_ref = client_ref
31
36
 
32
37
  def __iter__(self):
33
38
  return self
@@ -43,6 +48,9 @@ class EventStream(Generic[T]):
43
48
 
44
49
 
45
50
  class EventStreamAsync(Generic[T]):
51
+ # Holds a reference to the SDK client to avoid it being garbage collected
52
+ # and cause termination of the underlying httpx client.
53
+ client_ref: Optional[object]
46
54
  response: httpx.Response
47
55
  generator: AsyncGenerator[T, None]
48
56
 
@@ -51,9 +59,11 @@ class EventStreamAsync(Generic[T]):
51
59
  response: httpx.Response,
52
60
  decoder: Callable[[str], T],
53
61
  sentinel: Optional[str] = None,
62
+ client_ref: Optional[object] = None,
54
63
  ):
55
64
  self.response = response
56
65
  self.generator = stream_events_async(response, decoder, sentinel)
66
+ self.client_ref = client_ref
57
67
 
58
68
  def __aiter__(self):
59
69
  return self