hiddenlayer-sdk 2.0.10__py3-none-any.whl → 3.0.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 (204) hide show
  1. hiddenlayer/__init__.py +109 -114
  2. hiddenlayer/_base_client.py +1995 -0
  3. hiddenlayer/_client.py +761 -0
  4. hiddenlayer/_compat.py +219 -0
  5. hiddenlayer/_constants.py +14 -0
  6. hiddenlayer/_exceptions.py +108 -0
  7. hiddenlayer/_files.py +123 -0
  8. hiddenlayer/_models.py +835 -0
  9. hiddenlayer/_oauth2.py +118 -0
  10. hiddenlayer/_qs.py +150 -0
  11. hiddenlayer/_resource.py +43 -0
  12. hiddenlayer/_response.py +832 -0
  13. hiddenlayer/_streaming.py +333 -0
  14. hiddenlayer/_types.py +260 -0
  15. hiddenlayer/_utils/__init__.py +64 -0
  16. hiddenlayer/_utils/_compat.py +45 -0
  17. hiddenlayer/_utils/_datetime_parse.py +136 -0
  18. hiddenlayer/_utils/_logs.py +25 -0
  19. hiddenlayer/_utils/_proxy.py +65 -0
  20. hiddenlayer/_utils/_reflection.py +42 -0
  21. hiddenlayer/_utils/_resources_proxy.py +24 -0
  22. hiddenlayer/_utils/_streams.py +12 -0
  23. hiddenlayer/_utils/_sync.py +86 -0
  24. hiddenlayer/_utils/_transform.py +457 -0
  25. hiddenlayer/_utils/_typing.py +156 -0
  26. hiddenlayer/_utils/_utils.py +421 -0
  27. hiddenlayer/_version.py +4 -0
  28. hiddenlayer/lib/.keep +4 -0
  29. hiddenlayer/lib/__init__.py +6 -0
  30. hiddenlayer/lib/community_scan.py +174 -0
  31. hiddenlayer/lib/model_scan.py +752 -0
  32. hiddenlayer/lib/scan_utils.py +142 -0
  33. hiddenlayer/pagination.py +127 -0
  34. hiddenlayer/resources/__init__.py +75 -0
  35. hiddenlayer/resources/interactions.py +205 -0
  36. hiddenlayer/resources/models/__init__.py +33 -0
  37. hiddenlayer/resources/models/cards.py +259 -0
  38. hiddenlayer/resources/models/models.py +284 -0
  39. hiddenlayer/resources/prompt_analyzer.py +207 -0
  40. hiddenlayer/resources/scans/__init__.py +61 -0
  41. hiddenlayer/resources/scans/jobs.py +499 -0
  42. hiddenlayer/resources/scans/results.py +169 -0
  43. hiddenlayer/resources/scans/scans.py +166 -0
  44. hiddenlayer/resources/scans/upload/__init__.py +33 -0
  45. hiddenlayer/resources/scans/upload/file.py +279 -0
  46. hiddenlayer/resources/scans/upload/upload.py +340 -0
  47. hiddenlayer/resources/sensors.py +575 -0
  48. hiddenlayer/types/__init__.py +16 -0
  49. hiddenlayer/types/interaction_analyze_params.py +62 -0
  50. hiddenlayer/types/interaction_analyze_response.py +199 -0
  51. hiddenlayer/types/model_retrieve_response.py +50 -0
  52. hiddenlayer/types/models/__init__.py +6 -0
  53. hiddenlayer/types/models/card_list_params.py +65 -0
  54. hiddenlayer/types/models/card_list_response.py +50 -0
  55. hiddenlayer/types/prompt_analyzer_create_params.py +23 -0
  56. hiddenlayer/types/prompt_analyzer_create_response.py +381 -0
  57. hiddenlayer/types/scans/__init__.py +14 -0
  58. hiddenlayer/types/scans/job_list_params.py +75 -0
  59. hiddenlayer/types/scans/job_list_response.py +22 -0
  60. hiddenlayer/types/scans/job_request_params.py +49 -0
  61. hiddenlayer/types/scans/job_retrieve_params.py +16 -0
  62. hiddenlayer/types/scans/result_sarif_response.py +7 -0
  63. hiddenlayer/types/scans/scan_job.py +46 -0
  64. hiddenlayer/types/scans/scan_report.py +367 -0
  65. hiddenlayer/types/scans/upload/__init__.py +6 -0
  66. hiddenlayer/types/scans/upload/file_add_response.py +24 -0
  67. hiddenlayer/types/scans/upload/file_complete_response.py +12 -0
  68. hiddenlayer/types/scans/upload_complete_all_response.py +12 -0
  69. hiddenlayer/types/scans/upload_start_params.py +34 -0
  70. hiddenlayer/types/scans/upload_start_response.py +12 -0
  71. hiddenlayer/types/sensor_create_params.py +24 -0
  72. hiddenlayer/types/sensor_create_response.py +33 -0
  73. hiddenlayer/types/sensor_query_params.py +39 -0
  74. hiddenlayer/types/sensor_query_response.py +43 -0
  75. hiddenlayer/types/sensor_retrieve_response.py +33 -0
  76. hiddenlayer/types/sensor_update_params.py +20 -0
  77. hiddenlayer/types/sensor_update_response.py +9 -0
  78. hiddenlayer_sdk-3.0.1.dist-info/METADATA +521 -0
  79. hiddenlayer_sdk-3.0.1.dist-info/RECORD +82 -0
  80. {hiddenlayer_sdk-2.0.10.dist-info → hiddenlayer_sdk-3.0.1.dist-info}/WHEEL +1 -2
  81. {hiddenlayer_sdk-2.0.10.dist-info → hiddenlayer_sdk-3.0.1.dist-info}/licenses/LICENSE +1 -1
  82. hiddenlayer/sdk/constants.py +0 -26
  83. hiddenlayer/sdk/exceptions.py +0 -12
  84. hiddenlayer/sdk/models.py +0 -58
  85. hiddenlayer/sdk/rest/__init__.py +0 -135
  86. hiddenlayer/sdk/rest/api/__init__.py +0 -10
  87. hiddenlayer/sdk/rest/api/aidr_predictive_api.py +0 -308
  88. hiddenlayer/sdk/rest/api/health_api.py +0 -272
  89. hiddenlayer/sdk/rest/api/model_api.py +0 -559
  90. hiddenlayer/sdk/rest/api/model_supply_chain_api.py +0 -4063
  91. hiddenlayer/sdk/rest/api/readiness_api.py +0 -272
  92. hiddenlayer/sdk/rest/api/sensor_api.py +0 -1432
  93. hiddenlayer/sdk/rest/api_client.py +0 -770
  94. hiddenlayer/sdk/rest/api_response.py +0 -21
  95. hiddenlayer/sdk/rest/configuration.py +0 -445
  96. hiddenlayer/sdk/rest/exceptions.py +0 -199
  97. hiddenlayer/sdk/rest/models/__init__.py +0 -113
  98. hiddenlayer/sdk/rest/models/address.py +0 -110
  99. hiddenlayer/sdk/rest/models/artifact.py +0 -155
  100. hiddenlayer/sdk/rest/models/artifact_change.py +0 -108
  101. hiddenlayer/sdk/rest/models/artifact_content.py +0 -101
  102. hiddenlayer/sdk/rest/models/artifact_location.py +0 -109
  103. hiddenlayer/sdk/rest/models/attachment.py +0 -129
  104. hiddenlayer/sdk/rest/models/begin_multi_file_upload200_response.py +0 -87
  105. hiddenlayer/sdk/rest/models/begin_multipart_file_upload200_response.py +0 -97
  106. hiddenlayer/sdk/rest/models/begin_multipart_file_upload200_response_parts_inner.py +0 -94
  107. hiddenlayer/sdk/rest/models/code_flow.py +0 -113
  108. hiddenlayer/sdk/rest/models/configuration_override.py +0 -108
  109. hiddenlayer/sdk/rest/models/conversion.py +0 -114
  110. hiddenlayer/sdk/rest/models/create_sensor_request.py +0 -95
  111. hiddenlayer/sdk/rest/models/edge.py +0 -108
  112. hiddenlayer/sdk/rest/models/edge_traversal.py +0 -122
  113. hiddenlayer/sdk/rest/models/errors_inner.py +0 -91
  114. hiddenlayer/sdk/rest/models/exception.py +0 -113
  115. hiddenlayer/sdk/rest/models/external_properties.py +0 -273
  116. hiddenlayer/sdk/rest/models/external_property_file_reference.py +0 -102
  117. hiddenlayer/sdk/rest/models/external_property_file_references.py +0 -240
  118. hiddenlayer/sdk/rest/models/file_details_v3.py +0 -139
  119. hiddenlayer/sdk/rest/models/file_result_v3.py +0 -117
  120. hiddenlayer/sdk/rest/models/file_scan_report_v3.py +0 -132
  121. hiddenlayer/sdk/rest/models/file_scan_reports_v3.py +0 -95
  122. hiddenlayer/sdk/rest/models/fix.py +0 -113
  123. hiddenlayer/sdk/rest/models/get_condensed_model_scan_reports200_response.py +0 -102
  124. hiddenlayer/sdk/rest/models/graph.py +0 -123
  125. hiddenlayer/sdk/rest/models/graph_traversal.py +0 -97
  126. hiddenlayer/sdk/rest/models/inventory_v3.py +0 -101
  127. hiddenlayer/sdk/rest/models/invocation.py +0 -199
  128. hiddenlayer/sdk/rest/models/location.py +0 -146
  129. hiddenlayer/sdk/rest/models/location_inner.py +0 -138
  130. hiddenlayer/sdk/rest/models/location_relationship.py +0 -107
  131. hiddenlayer/sdk/rest/models/logical_location.py +0 -104
  132. hiddenlayer/sdk/rest/models/message.py +0 -92
  133. hiddenlayer/sdk/rest/models/mitre_atlas_inner.py +0 -110
  134. hiddenlayer/sdk/rest/models/model.py +0 -103
  135. hiddenlayer/sdk/rest/models/model_inventory_info.py +0 -103
  136. hiddenlayer/sdk/rest/models/model_version.py +0 -97
  137. hiddenlayer/sdk/rest/models/multi_file_upload_request_v3.py +0 -97
  138. hiddenlayer/sdk/rest/models/multiformat_message_string.py +0 -95
  139. hiddenlayer/sdk/rest/models/node.py +0 -122
  140. hiddenlayer/sdk/rest/models/notification.py +0 -157
  141. hiddenlayer/sdk/rest/models/notify_model_scan_completed200_response.py +0 -87
  142. hiddenlayer/sdk/rest/models/paged_response_with_total.py +0 -94
  143. hiddenlayer/sdk/rest/models/pagination_v3.py +0 -95
  144. hiddenlayer/sdk/rest/models/physical_location.py +0 -94
  145. hiddenlayer/sdk/rest/models/problem_details.py +0 -103
  146. hiddenlayer/sdk/rest/models/property_bag.py +0 -101
  147. hiddenlayer/sdk/rest/models/rectangle.py +0 -110
  148. hiddenlayer/sdk/rest/models/region.py +0 -127
  149. hiddenlayer/sdk/rest/models/replacement.py +0 -103
  150. hiddenlayer/sdk/rest/models/reporting_configuration.py +0 -113
  151. hiddenlayer/sdk/rest/models/reporting_descriptor.py +0 -162
  152. hiddenlayer/sdk/rest/models/reporting_descriptor_reference.py +0 -103
  153. hiddenlayer/sdk/rest/models/reporting_descriptor_relationship.py +0 -115
  154. hiddenlayer/sdk/rest/models/result.py +0 -312
  155. hiddenlayer/sdk/rest/models/result_provenance.py +0 -133
  156. hiddenlayer/sdk/rest/models/rule_details_inner.py +0 -102
  157. hiddenlayer/sdk/rest/models/run.py +0 -318
  158. hiddenlayer/sdk/rest/models/run_automation_details.py +0 -129
  159. hiddenlayer/sdk/rest/models/sarif210.py +0 -123
  160. hiddenlayer/sdk/rest/models/scan_create_request.py +0 -87
  161. hiddenlayer/sdk/rest/models/scan_detection_v3.py +0 -159
  162. hiddenlayer/sdk/rest/models/scan_detection_v31.py +0 -158
  163. hiddenlayer/sdk/rest/models/scan_header_v3.py +0 -129
  164. hiddenlayer/sdk/rest/models/scan_job.py +0 -115
  165. hiddenlayer/sdk/rest/models/scan_job_access.py +0 -97
  166. hiddenlayer/sdk/rest/models/scan_model_details_v3.py +0 -99
  167. hiddenlayer/sdk/rest/models/scan_model_details_v31.py +0 -97
  168. hiddenlayer/sdk/rest/models/scan_model_ids_v3.py +0 -89
  169. hiddenlayer/sdk/rest/models/scan_report_v3.py +0 -139
  170. hiddenlayer/sdk/rest/models/scan_results_map_v3.py +0 -105
  171. hiddenlayer/sdk/rest/models/scan_results_v3.py +0 -120
  172. hiddenlayer/sdk/rest/models/security_posture.py +0 -89
  173. hiddenlayer/sdk/rest/models/sensor.py +0 -100
  174. hiddenlayer/sdk/rest/models/sensor_query_response.py +0 -101
  175. hiddenlayer/sdk/rest/models/sensor_sor_model_card_query_response.py +0 -101
  176. hiddenlayer/sdk/rest/models/sensor_sor_model_card_response.py +0 -127
  177. hiddenlayer/sdk/rest/models/sensor_sor_query_filter.py +0 -108
  178. hiddenlayer/sdk/rest/models/sensor_sor_query_request.py +0 -109
  179. hiddenlayer/sdk/rest/models/special_locations.py +0 -97
  180. hiddenlayer/sdk/rest/models/stack.py +0 -113
  181. hiddenlayer/sdk/rest/models/stack_frame.py +0 -104
  182. hiddenlayer/sdk/rest/models/submission_response.py +0 -95
  183. hiddenlayer/sdk/rest/models/submission_v2.py +0 -109
  184. hiddenlayer/sdk/rest/models/suppression.py +0 -133
  185. hiddenlayer/sdk/rest/models/thread_flow.py +0 -144
  186. hiddenlayer/sdk/rest/models/thread_flow_location.py +0 -166
  187. hiddenlayer/sdk/rest/models/tool.py +0 -107
  188. hiddenlayer/sdk/rest/models/tool_component.py +0 -251
  189. hiddenlayer/sdk/rest/models/tool_component_reference.py +0 -108
  190. hiddenlayer/sdk/rest/models/translation_metadata.py +0 -110
  191. hiddenlayer/sdk/rest/models/validation_error_model.py +0 -99
  192. hiddenlayer/sdk/rest/models/version_control_details.py +0 -108
  193. hiddenlayer/sdk/rest/models/web_request.py +0 -112
  194. hiddenlayer/sdk/rest/models/web_response.py +0 -112
  195. hiddenlayer/sdk/rest/rest.py +0 -257
  196. hiddenlayer/sdk/services/__init__.py +0 -0
  197. hiddenlayer/sdk/services/aidr_predictive.py +0 -130
  198. hiddenlayer/sdk/services/model_scan.py +0 -505
  199. hiddenlayer/sdk/utils.py +0 -92
  200. hiddenlayer/sdk/version.py +0 -1
  201. hiddenlayer_sdk-2.0.10.dist-info/METADATA +0 -368
  202. hiddenlayer_sdk-2.0.10.dist-info/RECORD +0 -126
  203. hiddenlayer_sdk-2.0.10.dist-info/top_level.txt +0 -1
  204. /hiddenlayer/{sdk/__init__.py → py.typed} +0 -0
hiddenlayer/_models.py ADDED
@@ -0,0 +1,835 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import inspect
5
+ from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
6
+ from datetime import date, datetime
7
+ from typing_extensions import (
8
+ List,
9
+ Unpack,
10
+ Literal,
11
+ ClassVar,
12
+ Protocol,
13
+ Required,
14
+ ParamSpec,
15
+ TypedDict,
16
+ TypeGuard,
17
+ final,
18
+ override,
19
+ runtime_checkable,
20
+ )
21
+
22
+ import pydantic
23
+ from pydantic.fields import FieldInfo
24
+
25
+ from ._types import (
26
+ Body,
27
+ IncEx,
28
+ Query,
29
+ ModelT,
30
+ Headers,
31
+ Timeout,
32
+ NotGiven,
33
+ AnyMapping,
34
+ HttpxRequestFiles,
35
+ )
36
+ from ._utils import (
37
+ PropertyInfo,
38
+ is_list,
39
+ is_given,
40
+ json_safe,
41
+ lru_cache,
42
+ is_mapping,
43
+ parse_date,
44
+ coerce_boolean,
45
+ parse_datetime,
46
+ strip_not_given,
47
+ extract_type_arg,
48
+ is_annotated_type,
49
+ is_type_alias_type,
50
+ strip_annotated_type,
51
+ )
52
+ from ._compat import (
53
+ PYDANTIC_V1,
54
+ ConfigDict,
55
+ GenericModel as BaseGenericModel,
56
+ get_args,
57
+ is_union,
58
+ parse_obj,
59
+ get_origin,
60
+ is_literal_type,
61
+ get_model_config,
62
+ get_model_fields,
63
+ field_get_default,
64
+ )
65
+ from ._constants import RAW_RESPONSE_HEADER
66
+
67
+ if TYPE_CHECKING:
68
+ from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema
69
+
70
+ __all__ = ["BaseModel", "GenericModel"]
71
+
72
+ _T = TypeVar("_T")
73
+ _BaseModelT = TypeVar("_BaseModelT", bound="BaseModel")
74
+
75
+ P = ParamSpec("P")
76
+
77
+
78
+ @runtime_checkable
79
+ class _ConfigProtocol(Protocol):
80
+ allow_population_by_field_name: bool
81
+
82
+
83
+ class BaseModel(pydantic.BaseModel):
84
+ if PYDANTIC_V1:
85
+
86
+ @property
87
+ @override
88
+ def model_fields_set(self) -> set[str]:
89
+ # a forwards-compat shim for pydantic v2
90
+ return self.__fields_set__ # type: ignore
91
+
92
+ class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated]
93
+ extra: Any = pydantic.Extra.allow # type: ignore
94
+ else:
95
+ model_config: ClassVar[ConfigDict] = ConfigDict(
96
+ extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true"))
97
+ )
98
+
99
+ def to_dict(
100
+ self,
101
+ *,
102
+ mode: Literal["json", "python"] = "python",
103
+ use_api_names: bool = True,
104
+ exclude_unset: bool = True,
105
+ exclude_defaults: bool = False,
106
+ exclude_none: bool = False,
107
+ warnings: bool = True,
108
+ ) -> dict[str, object]:
109
+ """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude.
110
+
111
+ By default, fields that were not set by the API will not be included,
112
+ and keys will match the API response, *not* the property names from the model.
113
+
114
+ For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property,
115
+ the output will use the `"fooBar"` key (unless `use_api_names=False` is passed).
116
+
117
+ Args:
118
+ mode:
119
+ If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`.
120
+ If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)`
121
+
122
+ use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`.
123
+ exclude_unset: Whether to exclude fields that have not been explicitly set.
124
+ exclude_defaults: Whether to exclude fields that are set to their default value from the output.
125
+ exclude_none: Whether to exclude fields that have a value of `None` from the output.
126
+ warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2.
127
+ """
128
+ return self.model_dump(
129
+ mode=mode,
130
+ by_alias=use_api_names,
131
+ exclude_unset=exclude_unset,
132
+ exclude_defaults=exclude_defaults,
133
+ exclude_none=exclude_none,
134
+ warnings=warnings,
135
+ )
136
+
137
+ def to_json(
138
+ self,
139
+ *,
140
+ indent: int | None = 2,
141
+ use_api_names: bool = True,
142
+ exclude_unset: bool = True,
143
+ exclude_defaults: bool = False,
144
+ exclude_none: bool = False,
145
+ warnings: bool = True,
146
+ ) -> str:
147
+ """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation).
148
+
149
+ By default, fields that were not set by the API will not be included,
150
+ and keys will match the API response, *not* the property names from the model.
151
+
152
+ For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property,
153
+ the output will use the `"fooBar"` key (unless `use_api_names=False` is passed).
154
+
155
+ Args:
156
+ indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2`
157
+ use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`.
158
+ exclude_unset: Whether to exclude fields that have not been explicitly set.
159
+ exclude_defaults: Whether to exclude fields that have the default value.
160
+ exclude_none: Whether to exclude fields that have a value of `None`.
161
+ warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2.
162
+ """
163
+ return self.model_dump_json(
164
+ indent=indent,
165
+ by_alias=use_api_names,
166
+ exclude_unset=exclude_unset,
167
+ exclude_defaults=exclude_defaults,
168
+ exclude_none=exclude_none,
169
+ warnings=warnings,
170
+ )
171
+
172
+ @override
173
+ def __str__(self) -> str:
174
+ # mypy complains about an invalid self arg
175
+ return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc]
176
+
177
+ # Override the 'construct' method in a way that supports recursive parsing without validation.
178
+ # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836.
179
+ @classmethod
180
+ @override
181
+ def construct( # pyright: ignore[reportIncompatibleMethodOverride]
182
+ __cls: Type[ModelT],
183
+ _fields_set: set[str] | None = None,
184
+ **values: object,
185
+ ) -> ModelT:
186
+ m = __cls.__new__(__cls)
187
+ fields_values: dict[str, object] = {}
188
+
189
+ config = get_model_config(__cls)
190
+ populate_by_name = (
191
+ config.allow_population_by_field_name
192
+ if isinstance(config, _ConfigProtocol)
193
+ else config.get("populate_by_name")
194
+ )
195
+
196
+ if _fields_set is None:
197
+ _fields_set = set()
198
+
199
+ model_fields = get_model_fields(__cls)
200
+ for name, field in model_fields.items():
201
+ key = field.alias
202
+ if key is None or (key not in values and populate_by_name):
203
+ key = name
204
+
205
+ if key in values:
206
+ fields_values[name] = _construct_field(value=values[key], field=field, key=key)
207
+ _fields_set.add(name)
208
+ else:
209
+ fields_values[name] = field_get_default(field)
210
+
211
+ extra_field_type = _get_extra_fields_type(__cls)
212
+
213
+ _extra = {}
214
+ for key, value in values.items():
215
+ if key not in model_fields:
216
+ parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value
217
+
218
+ if PYDANTIC_V1:
219
+ _fields_set.add(key)
220
+ fields_values[key] = parsed
221
+ else:
222
+ _extra[key] = parsed
223
+
224
+ object.__setattr__(m, "__dict__", fields_values)
225
+
226
+ if PYDANTIC_V1:
227
+ # init_private_attributes() does not exist in v2
228
+ m._init_private_attributes() # type: ignore
229
+
230
+ # copied from Pydantic v1's `construct()` method
231
+ object.__setattr__(m, "__fields_set__", _fields_set)
232
+ else:
233
+ # these properties are copied from Pydantic's `model_construct()` method
234
+ object.__setattr__(m, "__pydantic_private__", None)
235
+ object.__setattr__(m, "__pydantic_extra__", _extra)
236
+ object.__setattr__(m, "__pydantic_fields_set__", _fields_set)
237
+
238
+ return m
239
+
240
+ if not TYPE_CHECKING:
241
+ # type checkers incorrectly complain about this assignment
242
+ # because the type signatures are technically different
243
+ # although not in practice
244
+ model_construct = construct
245
+
246
+ if PYDANTIC_V1:
247
+ # we define aliases for some of the new pydantic v2 methods so
248
+ # that we can just document these methods without having to specify
249
+ # a specific pydantic version as some users may not know which
250
+ # pydantic version they are currently using
251
+
252
+ @override
253
+ def model_dump(
254
+ self,
255
+ *,
256
+ mode: Literal["json", "python"] | str = "python",
257
+ include: IncEx | None = None,
258
+ exclude: IncEx | None = None,
259
+ by_alias: bool | None = None,
260
+ exclude_unset: bool = False,
261
+ exclude_defaults: bool = False,
262
+ exclude_none: bool = False,
263
+ round_trip: bool = False,
264
+ warnings: bool | Literal["none", "warn", "error"] = True,
265
+ context: dict[str, Any] | None = None,
266
+ serialize_as_any: bool = False,
267
+ fallback: Callable[[Any], Any] | None = None,
268
+ ) -> dict[str, Any]:
269
+ """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump
270
+
271
+ Generate a dictionary representation of the model, optionally specifying which fields to include or exclude.
272
+
273
+ Args:
274
+ mode: The mode in which `to_python` should run.
275
+ If mode is 'json', the dictionary will only contain JSON serializable types.
276
+ If mode is 'python', the dictionary may contain any Python objects.
277
+ include: A list of fields to include in the output.
278
+ exclude: A list of fields to exclude from the output.
279
+ by_alias: Whether to use the field's alias in the dictionary key if defined.
280
+ exclude_unset: Whether to exclude fields that are unset or None from the output.
281
+ exclude_defaults: Whether to exclude fields that are set to their default value from the output.
282
+ exclude_none: Whether to exclude fields that have a value of `None` from the output.
283
+ round_trip: Whether to enable serialization and deserialization round-trip support.
284
+ warnings: Whether to log warnings when invalid fields are encountered.
285
+
286
+ Returns:
287
+ A dictionary representation of the model.
288
+ """
289
+ if mode not in {"json", "python"}:
290
+ raise ValueError("mode must be either 'json' or 'python'")
291
+ if round_trip != False:
292
+ raise ValueError("round_trip is only supported in Pydantic v2")
293
+ if warnings != True:
294
+ raise ValueError("warnings is only supported in Pydantic v2")
295
+ if context is not None:
296
+ raise ValueError("context is only supported in Pydantic v2")
297
+ if serialize_as_any != False:
298
+ raise ValueError("serialize_as_any is only supported in Pydantic v2")
299
+ if fallback is not None:
300
+ raise ValueError("fallback is only supported in Pydantic v2")
301
+ dumped = super().dict( # pyright: ignore[reportDeprecated]
302
+ include=include,
303
+ exclude=exclude,
304
+ by_alias=by_alias if by_alias is not None else False,
305
+ exclude_unset=exclude_unset,
306
+ exclude_defaults=exclude_defaults,
307
+ exclude_none=exclude_none,
308
+ )
309
+
310
+ return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped
311
+
312
+ @override
313
+ def model_dump_json(
314
+ self,
315
+ *,
316
+ indent: int | None = None,
317
+ include: IncEx | None = None,
318
+ exclude: IncEx | None = None,
319
+ by_alias: bool | None = None,
320
+ exclude_unset: bool = False,
321
+ exclude_defaults: bool = False,
322
+ exclude_none: bool = False,
323
+ round_trip: bool = False,
324
+ warnings: bool | Literal["none", "warn", "error"] = True,
325
+ context: dict[str, Any] | None = None,
326
+ fallback: Callable[[Any], Any] | None = None,
327
+ serialize_as_any: bool = False,
328
+ ) -> str:
329
+ """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json
330
+
331
+ Generates a JSON representation of the model using Pydantic's `to_json` method.
332
+
333
+ Args:
334
+ indent: Indentation to use in the JSON output. If None is passed, the output will be compact.
335
+ include: Field(s) to include in the JSON output. Can take either a string or set of strings.
336
+ exclude: Field(s) to exclude from the JSON output. Can take either a string or set of strings.
337
+ by_alias: Whether to serialize using field aliases.
338
+ exclude_unset: Whether to exclude fields that have not been explicitly set.
339
+ exclude_defaults: Whether to exclude fields that have the default value.
340
+ exclude_none: Whether to exclude fields that have a value of `None`.
341
+ round_trip: Whether to use serialization/deserialization between JSON and class instance.
342
+ warnings: Whether to show any warnings that occurred during serialization.
343
+
344
+ Returns:
345
+ A JSON string representation of the model.
346
+ """
347
+ if round_trip != False:
348
+ raise ValueError("round_trip is only supported in Pydantic v2")
349
+ if warnings != True:
350
+ raise ValueError("warnings is only supported in Pydantic v2")
351
+ if context is not None:
352
+ raise ValueError("context is only supported in Pydantic v2")
353
+ if serialize_as_any != False:
354
+ raise ValueError("serialize_as_any is only supported in Pydantic v2")
355
+ if fallback is not None:
356
+ raise ValueError("fallback is only supported in Pydantic v2")
357
+ return super().json( # type: ignore[reportDeprecated]
358
+ indent=indent,
359
+ include=include,
360
+ exclude=exclude,
361
+ by_alias=by_alias if by_alias is not None else False,
362
+ exclude_unset=exclude_unset,
363
+ exclude_defaults=exclude_defaults,
364
+ exclude_none=exclude_none,
365
+ )
366
+
367
+
368
+ def _construct_field(value: object, field: FieldInfo, key: str) -> object:
369
+ if value is None:
370
+ return field_get_default(field)
371
+
372
+ if PYDANTIC_V1:
373
+ type_ = cast(type, field.outer_type_) # type: ignore
374
+ else:
375
+ type_ = field.annotation # type: ignore
376
+
377
+ if type_ is None:
378
+ raise RuntimeError(f"Unexpected field type is None for {key}")
379
+
380
+ return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None))
381
+
382
+
383
+ def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None:
384
+ if PYDANTIC_V1:
385
+ # TODO
386
+ return None
387
+
388
+ schema = cls.__pydantic_core_schema__
389
+ if schema["type"] == "model":
390
+ fields = schema["schema"]
391
+ if fields["type"] == "model-fields":
392
+ extras = fields.get("extras_schema")
393
+ if extras and "cls" in extras:
394
+ # mypy can't narrow the type
395
+ return extras["cls"] # type: ignore[no-any-return]
396
+
397
+ return None
398
+
399
+
400
+ def is_basemodel(type_: type) -> bool:
401
+ """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`"""
402
+ if is_union(type_):
403
+ for variant in get_args(type_):
404
+ if is_basemodel(variant):
405
+ return True
406
+
407
+ return False
408
+
409
+ return is_basemodel_type(type_)
410
+
411
+
412
+ def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]:
413
+ origin = get_origin(type_) or type_
414
+ if not inspect.isclass(origin):
415
+ return False
416
+ return issubclass(origin, BaseModel) or issubclass(origin, GenericModel)
417
+
418
+
419
+ def build(
420
+ base_model_cls: Callable[P, _BaseModelT],
421
+ *args: P.args,
422
+ **kwargs: P.kwargs,
423
+ ) -> _BaseModelT:
424
+ """Construct a BaseModel class without validation.
425
+
426
+ This is useful for cases where you need to instantiate a `BaseModel`
427
+ from an API response as this provides type-safe params which isn't supported
428
+ by helpers like `construct_type()`.
429
+
430
+ ```py
431
+ build(MyModel, my_field_a="foo", my_field_b=123)
432
+ ```
433
+ """
434
+ if args:
435
+ raise TypeError(
436
+ "Received positional arguments which are not supported; Keyword arguments must be used instead",
437
+ )
438
+
439
+ return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs))
440
+
441
+
442
+ def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T:
443
+ """Loose coercion to the expected type with construction of nested values.
444
+
445
+ Note: the returned value from this function is not guaranteed to match the
446
+ given type.
447
+ """
448
+ return cast(_T, construct_type(value=value, type_=type_))
449
+
450
+
451
+ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object:
452
+ """Loose coercion to the expected type with construction of nested values.
453
+
454
+ If the given value does not match the expected type then it is returned as-is.
455
+ """
456
+
457
+ # store a reference to the original type we were given before we extract any inner
458
+ # types so that we can properly resolve forward references in `TypeAliasType` annotations
459
+ original_type = None
460
+
461
+ # we allow `object` as the input type because otherwise, passing things like
462
+ # `Literal['value']` will be reported as a type error by type checkers
463
+ type_ = cast("type[object]", type_)
464
+ if is_type_alias_type(type_):
465
+ original_type = type_ # type: ignore[unreachable]
466
+ type_ = type_.__value__ # type: ignore[unreachable]
467
+
468
+ # unwrap `Annotated[T, ...]` -> `T`
469
+ if metadata is not None and len(metadata) > 0:
470
+ meta: tuple[Any, ...] = tuple(metadata)
471
+ elif is_annotated_type(type_):
472
+ meta = get_args(type_)[1:]
473
+ type_ = extract_type_arg(type_, 0)
474
+ else:
475
+ meta = tuple()
476
+
477
+ # we need to use the origin class for any types that are subscripted generics
478
+ # e.g. Dict[str, object]
479
+ origin = get_origin(type_) or type_
480
+ args = get_args(type_)
481
+
482
+ if is_union(origin):
483
+ try:
484
+ return validate_type(type_=cast("type[object]", original_type or type_), value=value)
485
+ except Exception:
486
+ pass
487
+
488
+ # if the type is a discriminated union then we want to construct the right variant
489
+ # in the union, even if the data doesn't match exactly, otherwise we'd break code
490
+ # that relies on the constructed class types, e.g.
491
+ #
492
+ # class FooType:
493
+ # kind: Literal['foo']
494
+ # value: str
495
+ #
496
+ # class BarType:
497
+ # kind: Literal['bar']
498
+ # value: int
499
+ #
500
+ # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then
501
+ # we'd end up constructing `FooType` when it should be `BarType`.
502
+ discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta)
503
+ if discriminator and is_mapping(value):
504
+ variant_value = value.get(discriminator.field_alias_from or discriminator.field_name)
505
+ if variant_value and isinstance(variant_value, str):
506
+ variant_type = discriminator.mapping.get(variant_value)
507
+ if variant_type:
508
+ return construct_type(type_=variant_type, value=value)
509
+
510
+ # if the data is not valid, use the first variant that doesn't fail while deserializing
511
+ for variant in args:
512
+ try:
513
+ return construct_type(value=value, type_=variant)
514
+ except Exception:
515
+ continue
516
+
517
+ raise RuntimeError(f"Could not convert data into a valid instance of {type_}")
518
+
519
+ if origin == dict:
520
+ if not is_mapping(value):
521
+ return value
522
+
523
+ _, items_type = get_args(type_) # Dict[_, items_type]
524
+ return {key: construct_type(value=item, type_=items_type) for key, item in value.items()}
525
+
526
+ if (
527
+ not is_literal_type(type_)
528
+ and inspect.isclass(origin)
529
+ and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel))
530
+ ):
531
+ if is_list(value):
532
+ return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value]
533
+
534
+ if is_mapping(value):
535
+ if issubclass(type_, BaseModel):
536
+ return type_.construct(**value) # type: ignore[arg-type]
537
+
538
+ return cast(Any, type_).construct(**value)
539
+
540
+ if origin == list:
541
+ if not is_list(value):
542
+ return value
543
+
544
+ inner_type = args[0] # List[inner_type]
545
+ return [construct_type(value=entry, type_=inner_type) for entry in value]
546
+
547
+ if origin == float:
548
+ if isinstance(value, int):
549
+ coerced = float(value)
550
+ if coerced != value:
551
+ return value
552
+ return coerced
553
+
554
+ return value
555
+
556
+ if type_ == datetime:
557
+ try:
558
+ return parse_datetime(value) # type: ignore
559
+ except Exception:
560
+ return value
561
+
562
+ if type_ == date:
563
+ try:
564
+ return parse_date(value) # type: ignore
565
+ except Exception:
566
+ return value
567
+
568
+ return value
569
+
570
+
571
+ @runtime_checkable
572
+ class CachedDiscriminatorType(Protocol):
573
+ __discriminator__: DiscriminatorDetails
574
+
575
+
576
+ class DiscriminatorDetails:
577
+ field_name: str
578
+ """The name of the discriminator field in the variant class, e.g.
579
+
580
+ ```py
581
+ class Foo(BaseModel):
582
+ type: Literal['foo']
583
+ ```
584
+
585
+ Will result in field_name='type'
586
+ """
587
+
588
+ field_alias_from: str | None
589
+ """The name of the discriminator field in the API response, e.g.
590
+
591
+ ```py
592
+ class Foo(BaseModel):
593
+ type: Literal['foo'] = Field(alias='type_from_api')
594
+ ```
595
+
596
+ Will result in field_alias_from='type_from_api'
597
+ """
598
+
599
+ mapping: dict[str, type]
600
+ """Mapping of discriminator value to variant type, e.g.
601
+
602
+ {'foo': FooVariant, 'bar': BarVariant}
603
+ """
604
+
605
+ def __init__(
606
+ self,
607
+ *,
608
+ mapping: dict[str, type],
609
+ discriminator_field: str,
610
+ discriminator_alias: str | None,
611
+ ) -> None:
612
+ self.mapping = mapping
613
+ self.field_name = discriminator_field
614
+ self.field_alias_from = discriminator_alias
615
+
616
+
617
+ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None:
618
+ if isinstance(union, CachedDiscriminatorType):
619
+ return union.__discriminator__
620
+
621
+ discriminator_field_name: str | None = None
622
+
623
+ for annotation in meta_annotations:
624
+ if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None:
625
+ discriminator_field_name = annotation.discriminator
626
+ break
627
+
628
+ if not discriminator_field_name:
629
+ return None
630
+
631
+ mapping: dict[str, type] = {}
632
+ discriminator_alias: str | None = None
633
+
634
+ for variant in get_args(union):
635
+ variant = strip_annotated_type(variant)
636
+ if is_basemodel_type(variant):
637
+ if PYDANTIC_V1:
638
+ field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
639
+ if not field_info:
640
+ continue
641
+
642
+ # Note: if one variant defines an alias then they all should
643
+ discriminator_alias = field_info.alias
644
+
645
+ if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation):
646
+ for entry in get_args(annotation):
647
+ if isinstance(entry, str):
648
+ mapping[entry] = variant
649
+ else:
650
+ field = _extract_field_schema_pv2(variant, discriminator_field_name)
651
+ if not field:
652
+ continue
653
+
654
+ # Note: if one variant defines an alias then they all should
655
+ discriminator_alias = field.get("serialization_alias")
656
+
657
+ field_schema = field["schema"]
658
+
659
+ if field_schema["type"] == "literal":
660
+ for entry in cast("LiteralSchema", field_schema)["expected"]:
661
+ if isinstance(entry, str):
662
+ mapping[entry] = variant
663
+
664
+ if not mapping:
665
+ return None
666
+
667
+ details = DiscriminatorDetails(
668
+ mapping=mapping,
669
+ discriminator_field=discriminator_field_name,
670
+ discriminator_alias=discriminator_alias,
671
+ )
672
+ cast(CachedDiscriminatorType, union).__discriminator__ = details
673
+ return details
674
+
675
+
676
+ def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None:
677
+ schema = model.__pydantic_core_schema__
678
+ if schema["type"] == "definitions":
679
+ schema = schema["schema"]
680
+
681
+ if schema["type"] != "model":
682
+ return None
683
+
684
+ schema = cast("ModelSchema", schema)
685
+ fields_schema = schema["schema"]
686
+ if fields_schema["type"] != "model-fields":
687
+ return None
688
+
689
+ fields_schema = cast("ModelFieldsSchema", fields_schema)
690
+ field = fields_schema["fields"].get(field_name)
691
+ if not field:
692
+ return None
693
+
694
+ return cast("ModelField", field) # pyright: ignore[reportUnnecessaryCast]
695
+
696
+
697
+ def validate_type(*, type_: type[_T], value: object) -> _T:
698
+ """Strict validation that the given value matches the expected type"""
699
+ if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel):
700
+ return cast(_T, parse_obj(type_, value))
701
+
702
+ return cast(_T, _validate_non_model_type(type_=type_, value=value))
703
+
704
+
705
+ def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None:
706
+ """Add a pydantic config for the given type.
707
+
708
+ Note: this is a no-op on Pydantic v1.
709
+ """
710
+ setattr(typ, "__pydantic_config__", config) # noqa: B010
711
+
712
+
713
+ # our use of subclassing here causes weirdness for type checkers,
714
+ # so we just pretend that we don't subclass
715
+ if TYPE_CHECKING:
716
+ GenericModel = BaseModel
717
+ else:
718
+
719
+ class GenericModel(BaseGenericModel, BaseModel):
720
+ pass
721
+
722
+
723
+ if not PYDANTIC_V1:
724
+ from pydantic import TypeAdapter as _TypeAdapter
725
+
726
+ _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter))
727
+
728
+ if TYPE_CHECKING:
729
+ from pydantic import TypeAdapter
730
+ else:
731
+ TypeAdapter = _CachedTypeAdapter
732
+
733
+ def _validate_non_model_type(*, type_: type[_T], value: object) -> _T:
734
+ return TypeAdapter(type_).validate_python(value)
735
+
736
+ elif not TYPE_CHECKING: # TODO: condition is weird
737
+
738
+ class RootModel(GenericModel, Generic[_T]):
739
+ """Used as a placeholder to easily convert runtime types to a Pydantic format
740
+ to provide validation.
741
+
742
+ For example:
743
+ ```py
744
+ validated = RootModel[int](__root__="5").__root__
745
+ # validated: 5
746
+ ```
747
+ """
748
+
749
+ __root__: _T
750
+
751
+ def _validate_non_model_type(*, type_: type[_T], value: object) -> _T:
752
+ model = _create_pydantic_model(type_).validate(value)
753
+ return cast(_T, model.__root__)
754
+
755
+ def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]:
756
+ return RootModel[type_] # type: ignore
757
+
758
+
759
+ class FinalRequestOptionsInput(TypedDict, total=False):
760
+ method: Required[str]
761
+ url: Required[str]
762
+ params: Query
763
+ headers: Headers
764
+ max_retries: int
765
+ timeout: float | Timeout | None
766
+ files: HttpxRequestFiles | None
767
+ idempotency_key: str
768
+ json_data: Body
769
+ extra_json: AnyMapping
770
+ follow_redirects: bool
771
+
772
+
773
+ @final
774
+ class FinalRequestOptions(pydantic.BaseModel):
775
+ method: str
776
+ url: str
777
+ params: Query = {}
778
+ headers: Union[Headers, NotGiven] = NotGiven()
779
+ max_retries: Union[int, NotGiven] = NotGiven()
780
+ timeout: Union[float, Timeout, None, NotGiven] = NotGiven()
781
+ files: Union[HttpxRequestFiles, None] = None
782
+ idempotency_key: Union[str, None] = None
783
+ post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
784
+ follow_redirects: Union[bool, None] = None
785
+
786
+ # It should be noted that we cannot use `json` here as that would override
787
+ # a BaseModel method in an incompatible fashion.
788
+ json_data: Union[Body, None] = None
789
+ extra_json: Union[AnyMapping, None] = None
790
+
791
+ if PYDANTIC_V1:
792
+
793
+ class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated]
794
+ arbitrary_types_allowed: bool = True
795
+ else:
796
+ model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
797
+
798
+ def get_max_retries(self, max_retries: int) -> int:
799
+ if isinstance(self.max_retries, NotGiven):
800
+ return max_retries
801
+ return self.max_retries
802
+
803
+ def _strip_raw_response_header(self) -> None:
804
+ if not is_given(self.headers):
805
+ return
806
+
807
+ if self.headers.get(RAW_RESPONSE_HEADER):
808
+ self.headers = {**self.headers}
809
+ self.headers.pop(RAW_RESPONSE_HEADER)
810
+
811
+ # override the `construct` method so that we can run custom transformations.
812
+ # this is necessary as we don't want to do any actual runtime type checking
813
+ # (which means we can't use validators) but we do want to ensure that `NotGiven`
814
+ # values are not present
815
+ #
816
+ # type ignore required because we're adding explicit types to `**values`
817
+ @classmethod
818
+ def construct( # type: ignore
819
+ cls,
820
+ _fields_set: set[str] | None = None,
821
+ **values: Unpack[FinalRequestOptionsInput],
822
+ ) -> FinalRequestOptions:
823
+ kwargs: dict[str, Any] = {
824
+ # we unconditionally call `strip_not_given` on any value
825
+ # as it will just ignore any non-mapping types
826
+ key: strip_not_given(value)
827
+ for key, value in values.items()
828
+ }
829
+ if PYDANTIC_V1:
830
+ return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated]
831
+ return super().model_construct(_fields_set, **kwargs)
832
+
833
+ if not TYPE_CHECKING:
834
+ # type checkers incorrectly complain about this assignment
835
+ model_construct = construct