hammad-python 0.0.13__py3-none-any.whl → 0.0.15__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.
- hammad_python-0.0.15.dist-info/METADATA +184 -0
- hammad_python-0.0.15.dist-info/RECORD +4 -0
- hammad/__init__.py +0 -180
- hammad/_core/__init__.py +0 -1
- hammad/_core/_utils/__init__.py +0 -4
- hammad/_core/_utils/_import_utils.py +0 -182
- hammad/ai/__init__.py +0 -59
- hammad/ai/_utils.py +0 -142
- hammad/ai/completions/__init__.py +0 -44
- hammad/ai/completions/client.py +0 -729
- hammad/ai/completions/create.py +0 -686
- hammad/ai/completions/types.py +0 -711
- hammad/ai/completions/utils.py +0 -374
- hammad/ai/embeddings/__init__.py +0 -35
- hammad/ai/embeddings/client/__init__.py +0 -1
- hammad/ai/embeddings/client/base_embeddings_client.py +0 -26
- hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +0 -200
- hammad/ai/embeddings/client/litellm_embeddings_client.py +0 -288
- hammad/ai/embeddings/create.py +0 -159
- hammad/ai/embeddings/types.py +0 -69
- hammad/base/__init__.py +0 -35
- hammad/base/fields.py +0 -546
- hammad/base/model.py +0 -1078
- hammad/base/utils.py +0 -280
- hammad/cache/__init__.py +0 -48
- hammad/cache/base_cache.py +0 -181
- hammad/cache/cache.py +0 -169
- hammad/cache/decorators.py +0 -261
- hammad/cache/file_cache.py +0 -80
- hammad/cache/ttl_cache.py +0 -74
- hammad/cli/__init__.py +0 -33
- hammad/cli/animations.py +0 -604
- hammad/cli/plugins.py +0 -781
- hammad/cli/styles/__init__.py +0 -55
- hammad/cli/styles/settings.py +0 -139
- hammad/cli/styles/types.py +0 -358
- hammad/cli/styles/utils.py +0 -480
- hammad/configuration/__init__.py +0 -35
- hammad/configuration/configuration.py +0 -564
- hammad/data/__init__.py +0 -39
- hammad/data/collections/__init__.py +0 -34
- hammad/data/collections/base_collection.py +0 -58
- hammad/data/collections/collection.py +0 -452
- hammad/data/collections/searchable_collection.py +0 -556
- hammad/data/collections/vector_collection.py +0 -603
- hammad/data/databases/__init__.py +0 -21
- hammad/data/databases/database.py +0 -902
- hammad/json/__init__.py +0 -21
- hammad/json/converters.py +0 -152
- hammad/logging/__init__.py +0 -35
- hammad/logging/decorators.py +0 -834
- hammad/logging/logger.py +0 -954
- hammad/multimodal/__init__.py +0 -24
- hammad/multimodal/audio.py +0 -96
- hammad/multimodal/image.py +0 -80
- hammad/multithreading/__init__.py +0 -304
- hammad/py.typed +0 -0
- hammad/pydantic/__init__.py +0 -43
- hammad/pydantic/converters.py +0 -623
- hammad/pydantic/models/__init__.py +0 -28
- hammad/pydantic/models/arbitrary_model.py +0 -46
- hammad/pydantic/models/cacheable_model.py +0 -79
- hammad/pydantic/models/fast_model.py +0 -318
- hammad/pydantic/models/function_model.py +0 -176
- hammad/pydantic/models/subscriptable_model.py +0 -63
- hammad/text/__init__.py +0 -82
- hammad/text/converters.py +0 -723
- hammad/text/markdown.py +0 -131
- hammad/text/text.py +0 -1066
- hammad/types/__init__.py +0 -11
- hammad/types/file.py +0 -358
- hammad/typing/__init__.py +0 -407
- hammad/web/__init__.py +0 -43
- hammad/web/http/__init__.py +0 -1
- hammad/web/http/client.py +0 -944
- hammad/web/models.py +0 -245
- hammad/web/openapi/__init__.py +0 -0
- hammad/web/openapi/client.py +0 -740
- hammad/web/search/__init__.py +0 -1
- hammad/web/search/client.py +0 -988
- hammad/web/utils.py +0 -472
- hammad/yaml/__init__.py +0 -30
- hammad/yaml/converters.py +0 -19
- hammad_python-0.0.13.dist-info/METADATA +0 -38
- hammad_python-0.0.13.dist-info/RECORD +0 -85
- {hammad_python-0.0.13.dist-info → hammad_python-0.0.15.dist-info}/WHEEL +0 -0
- {hammad_python-0.0.13.dist-info → hammad_python-0.0.15.dist-info}/licenses/LICENSE +0 -0
hammad/pydantic/converters.py
DELETED
@@ -1,623 +0,0 @@
|
|
1
|
-
"""hammad.utils.pydantic.converters
|
2
|
-
|
3
|
-
Contains various converters for converting various objects into
|
4
|
-
a Pydantic model. These converters are used to convert
|
5
|
-
various objects into a Pydantic model, such as types,
|
6
|
-
docstrings, and other objects."""
|
7
|
-
|
8
|
-
import inspect
|
9
|
-
import logging
|
10
|
-
from dataclasses import is_dataclass, fields as dataclass_fields, MISSING
|
11
|
-
from docstring_parser import parse
|
12
|
-
from typing import (
|
13
|
-
Any,
|
14
|
-
Dict,
|
15
|
-
Literal,
|
16
|
-
Optional,
|
17
|
-
Type,
|
18
|
-
Union,
|
19
|
-
Mapping,
|
20
|
-
get_type_hints,
|
21
|
-
Callable,
|
22
|
-
Sequence,
|
23
|
-
TypeVar,
|
24
|
-
Tuple,
|
25
|
-
List,
|
26
|
-
overload,
|
27
|
-
cast,
|
28
|
-
)
|
29
|
-
from pydantic import BaseModel, Field, create_model
|
30
|
-
|
31
|
-
from ..cache.decorators import cached
|
32
|
-
|
33
|
-
logger = logging.getLogger(__name__)
|
34
|
-
|
35
|
-
__all__ = [
|
36
|
-
"is_pydantic_model_class",
|
37
|
-
"get_pydantic_fields_from_function",
|
38
|
-
"convert_to_pydantic_field",
|
39
|
-
"convert_to_pydantic_model",
|
40
|
-
"create_selection_pydantic_model",
|
41
|
-
"create_confirmation_pydantic_model",
|
42
|
-
"convert_dataclass_to_pydantic_model",
|
43
|
-
"convert_type_to_pydantic_model",
|
44
|
-
"convert_function_to_pydantic_model",
|
45
|
-
"convert_sequence_to_pydantic_model",
|
46
|
-
"convert_dict_to_pydantic_model",
|
47
|
-
]
|
48
|
-
|
49
|
-
|
50
|
-
# -----------------------------------------------------------------------------
|
51
|
-
# Types & Constants
|
52
|
-
# -----------------------------------------------------------------------------
|
53
|
-
|
54
|
-
BaseModelType = TypeVar("BaseModelType", bound=BaseModel)
|
55
|
-
"""Helper type for Pydantic model classes."""
|
56
|
-
|
57
|
-
|
58
|
-
JSON_TYPE_MAPPING: Mapping[Any, Tuple[str, Any]] = {
|
59
|
-
int: ("int", int),
|
60
|
-
float: ("float", float),
|
61
|
-
bool: ("bool", bool),
|
62
|
-
str: ("str", str),
|
63
|
-
bytes: ("bytes", bytes),
|
64
|
-
list: ("list", list),
|
65
|
-
tuple: ("tuple", tuple),
|
66
|
-
dict: ("dict", dict),
|
67
|
-
set: ("set", set),
|
68
|
-
frozenset: ("frozenset", frozenset),
|
69
|
-
Any: ("any", Any),
|
70
|
-
None: ("none", None),
|
71
|
-
Union: ("union", Union),
|
72
|
-
Optional: ("optional", Optional),
|
73
|
-
}
|
74
|
-
"""
|
75
|
-
A mapping of types to their string representations. Used for hinting & JSON schema
|
76
|
-
generation.
|
77
|
-
"""
|
78
|
-
|
79
|
-
|
80
|
-
# -----------------------------------------------------------------------------
|
81
|
-
# Pydantic Model Utils
|
82
|
-
# -----------------------------------------------------------------------------
|
83
|
-
|
84
|
-
|
85
|
-
def is_pydantic_model_class(obj: Any) -> bool:
|
86
|
-
"""
|
87
|
-
Checks if an object is a Pydantic model class.
|
88
|
-
"""
|
89
|
-
return isinstance(obj, type) and issubclass(obj, BaseModel)
|
90
|
-
|
91
|
-
|
92
|
-
def get_pydantic_fields_from_function(func: Callable) -> Dict[str, Tuple[Type, Field]]:
|
93
|
-
"""
|
94
|
-
Extracts Pydantic fields from a function's signature and docstring.
|
95
|
-
Returns a dictionary mapping field names to (type, Pydantic Field) tuples.
|
96
|
-
|
97
|
-
Args:
|
98
|
-
func: The function to extract Pydantic fields from.
|
99
|
-
|
100
|
-
Returns:
|
101
|
-
A dictionary mapping field names to (type, Pydantic Field) tuples.
|
102
|
-
"""
|
103
|
-
try:
|
104
|
-
hints = get_type_hints(func)
|
105
|
-
fields_dict: Dict[str, Tuple[Type, Field]] = {}
|
106
|
-
doc_info = parse(func.__doc__ or "")
|
107
|
-
|
108
|
-
for param_name, param_type in hints.items():
|
109
|
-
if param_name == "return":
|
110
|
-
continue
|
111
|
-
|
112
|
-
description = ""
|
113
|
-
if doc_info.params:
|
114
|
-
description = (
|
115
|
-
next(
|
116
|
-
(
|
117
|
-
p.description
|
118
|
-
for p in doc_info.params
|
119
|
-
if p.arg_name == param_name
|
120
|
-
),
|
121
|
-
"",
|
122
|
-
)
|
123
|
-
or ""
|
124
|
-
)
|
125
|
-
|
126
|
-
default_value = ...
|
127
|
-
param = inspect.signature(func).parameters.get(param_name)
|
128
|
-
if param and param.default is not inspect.Parameter.empty:
|
129
|
-
default_value = param.default
|
130
|
-
|
131
|
-
fields_dict[param_name] = (
|
132
|
-
param_type,
|
133
|
-
Field(default=default_value, description=description),
|
134
|
-
)
|
135
|
-
return fields_dict
|
136
|
-
except Exception as e:
|
137
|
-
logger.error(
|
138
|
-
f"Error extracting function fields for {getattr(func, '__name__', 'unknown function')}: {e}"
|
139
|
-
)
|
140
|
-
return {}
|
141
|
-
|
142
|
-
|
143
|
-
@cached
|
144
|
-
def convert_to_pydantic_field(
|
145
|
-
type_hint: Type,
|
146
|
-
index: Optional[int] = None,
|
147
|
-
description: Optional[str] = None,
|
148
|
-
default: Any = ...,
|
149
|
-
) -> Dict[str, Tuple[Type, Field]]:
|
150
|
-
"""
|
151
|
-
Creates a Pydantic field definition from a type hint.
|
152
|
-
Returns a dictionary mapping a generated field name to its (type, Field) tuple.
|
153
|
-
"""
|
154
|
-
try:
|
155
|
-
base_name, _ = JSON_TYPE_MAPPING.get(type_hint, ("value", type_hint))
|
156
|
-
field_name = f"value_{index}" if index is not None else "value"
|
157
|
-
return {
|
158
|
-
field_name: (
|
159
|
-
type_hint,
|
160
|
-
Field(default=default, description=description or ""),
|
161
|
-
)
|
162
|
-
}
|
163
|
-
except Exception as e:
|
164
|
-
logger.error(f"Error creating Pydantic field mapping for type {type_hint}: {e}")
|
165
|
-
raise
|
166
|
-
|
167
|
-
|
168
|
-
# -----------------------------------------------------------------------------
|
169
|
-
# Simplified Model Creation
|
170
|
-
# -----------------------------------------------------------------------------
|
171
|
-
|
172
|
-
|
173
|
-
# -----------------------------------------------------------------------------
|
174
|
-
# Helpers (Private)
|
175
|
-
# -----------------------------------------------------------------------------
|
176
|
-
|
177
|
-
|
178
|
-
@cached
|
179
|
-
def convert_dataclass_to_pydantic_model(
|
180
|
-
target: Union[Type, Any], # NOTE: DATACLASS TYPE OR INSTANCE
|
181
|
-
init: bool,
|
182
|
-
name: Optional[str],
|
183
|
-
description: Optional[str],
|
184
|
-
) -> Union[Type[BaseModel], BaseModel]:
|
185
|
-
# Determine if we're dealing with a type or instance
|
186
|
-
is_instance = not isinstance(target, type)
|
187
|
-
dataclass_type = type(target) if is_instance else target
|
188
|
-
|
189
|
-
model_name = name or dataclass_type.__name__
|
190
|
-
doc_info = parse(dataclass_type.__doc__ or "")
|
191
|
-
model_doc = description or doc_info.short_description
|
192
|
-
|
193
|
-
pydantic_fields: Dict[str, Tuple[Type, Field]] = {}
|
194
|
-
for dc_field in dataclass_fields(dataclass_type):
|
195
|
-
field_type = dc_field.type
|
196
|
-
field_default = dc_field.default if dc_field.default is not MISSING else ... # type: ignore
|
197
|
-
if dc_field.default_factory is not MISSING: # type: ignore
|
198
|
-
field_default = Field(default_factory=dc_field.default_factory)
|
199
|
-
|
200
|
-
field_description = ""
|
201
|
-
if doc_info.params:
|
202
|
-
field_description = (
|
203
|
-
next(
|
204
|
-
(
|
205
|
-
p.description
|
206
|
-
for p in doc_info.params
|
207
|
-
if p.arg_name == dc_field.name
|
208
|
-
),
|
209
|
-
"",
|
210
|
-
)
|
211
|
-
or ""
|
212
|
-
)
|
213
|
-
|
214
|
-
pydantic_fields[dc_field.name] = (
|
215
|
-
field_type,
|
216
|
-
Field(default=field_default, description=field_description),
|
217
|
-
)
|
218
|
-
|
219
|
-
model_class = create_model(model_name, __doc__=model_doc, **pydantic_fields)
|
220
|
-
|
221
|
-
if init and is_instance:
|
222
|
-
instance_data = {
|
223
|
-
f.name: getattr(target, f.name) for f in dataclass_fields(dataclass_type)
|
224
|
-
}
|
225
|
-
return model_class(**instance_data)
|
226
|
-
return model_class
|
227
|
-
|
228
|
-
|
229
|
-
@cached
|
230
|
-
def convert_type_to_pydantic_model(
|
231
|
-
target: Type,
|
232
|
-
name: Optional[str],
|
233
|
-
description: Optional[str],
|
234
|
-
field_name: Optional[str],
|
235
|
-
default: Any,
|
236
|
-
) -> Type[BaseModel]:
|
237
|
-
model_name = name or "GeneratedModel"
|
238
|
-
field_mapping = convert_to_pydantic_field(
|
239
|
-
target, description=description, default=default
|
240
|
-
)
|
241
|
-
|
242
|
-
if field_name: # Override default field name "value"
|
243
|
-
current_field_def = list(field_mapping.values())[0]
|
244
|
-
field_mapping = {field_name: current_field_def}
|
245
|
-
|
246
|
-
return create_model(model_name, __doc__=(description or ""), **field_mapping)
|
247
|
-
|
248
|
-
|
249
|
-
@cached
|
250
|
-
def convert_function_to_pydantic_model(
|
251
|
-
target: Callable,
|
252
|
-
name: Optional[str],
|
253
|
-
description: Optional[str],
|
254
|
-
) -> Type[BaseModel]:
|
255
|
-
model_name = name or target.__name__
|
256
|
-
doc_info = parse(target.__doc__ or "")
|
257
|
-
model_doc = description or doc_info.short_description
|
258
|
-
|
259
|
-
fields = get_pydantic_fields_from_function(target)
|
260
|
-
return create_model(model_name, __doc__=model_doc, **fields)
|
261
|
-
|
262
|
-
|
263
|
-
@cached
|
264
|
-
def convert_sequence_to_pydantic_model(
|
265
|
-
target: Sequence[Type],
|
266
|
-
name: Optional[str],
|
267
|
-
description: Optional[str],
|
268
|
-
field_name: Optional[str],
|
269
|
-
default: Any,
|
270
|
-
) -> Type[BaseModel]:
|
271
|
-
if not target:
|
272
|
-
raise ValueError("Cannot create Pydantic model from empty sequence")
|
273
|
-
|
274
|
-
model_name = name or "GeneratedModel"
|
275
|
-
pydantic_fields: Dict[str, Tuple[Type, Field]] = {}
|
276
|
-
|
277
|
-
for i, type_hint in enumerate(target):
|
278
|
-
if not isinstance(type_hint, type):
|
279
|
-
raise ValueError(
|
280
|
-
f"Sequence elements must be types, got {type_hint} at index {i}"
|
281
|
-
)
|
282
|
-
|
283
|
-
field_desc = description if i == 0 and field_name else None
|
284
|
-
field_def_default = default if i == 0 and field_name else ...
|
285
|
-
|
286
|
-
# Use provided field_name for the first element if specified
|
287
|
-
current_field_name_override = field_name if i == 0 else None
|
288
|
-
|
289
|
-
# Generate field(s) from type_hint
|
290
|
-
temp_field_def = convert_to_pydantic_field(
|
291
|
-
type_hint,
|
292
|
-
index=None if current_field_name_override else i,
|
293
|
-
description=field_desc,
|
294
|
-
default=field_def_default,
|
295
|
-
)
|
296
|
-
|
297
|
-
actual_field_name = list(temp_field_def.keys())[0]
|
298
|
-
actual_type_info = list(temp_field_def.values())[0]
|
299
|
-
|
300
|
-
if current_field_name_override:
|
301
|
-
pydantic_fields[current_field_name_override] = actual_type_info
|
302
|
-
else:
|
303
|
-
pydantic_fields[actual_field_name] = actual_type_info
|
304
|
-
|
305
|
-
return create_model(model_name, __doc__=(description or ""), **pydantic_fields)
|
306
|
-
|
307
|
-
|
308
|
-
@cached
|
309
|
-
def convert_dict_to_pydantic_model(
|
310
|
-
target: Dict[str, Any],
|
311
|
-
init: bool,
|
312
|
-
name: Optional[str],
|
313
|
-
description: Optional[str],
|
314
|
-
) -> Union[Type[BaseModel], BaseModel]:
|
315
|
-
model_name = name or "GeneratedModel"
|
316
|
-
|
317
|
-
pydantic_fields: Dict[str, Tuple[Type, Field]] = {}
|
318
|
-
for k, v in target.items():
|
319
|
-
pydantic_fields[k] = (type(v), Field(default=v if init else ...))
|
320
|
-
|
321
|
-
model_class = create_model(
|
322
|
-
model_name, __doc__=(description or ""), **pydantic_fields
|
323
|
-
)
|
324
|
-
|
325
|
-
if init:
|
326
|
-
return model_class(**target)
|
327
|
-
return model_class
|
328
|
-
|
329
|
-
|
330
|
-
@cached
|
331
|
-
def _reconvert_to_pydantic_model_from_basemodel_instance(
|
332
|
-
target: BaseModel,
|
333
|
-
name: Optional[str],
|
334
|
-
description: Optional[str],
|
335
|
-
) -> BaseModel:
|
336
|
-
model_name = name or target.__class__.__name__
|
337
|
-
doc_info = parse(target.__class__.__doc__ or "")
|
338
|
-
model_doc = description or doc_info.short_description
|
339
|
-
|
340
|
-
instance_data = target.model_dump()
|
341
|
-
pydantic_fields: Dict[str, Tuple[Type, Field]] = {}
|
342
|
-
for k, v_instance in instance_data.items():
|
343
|
-
original_field_info = target.__class__.model_fields.get(k)
|
344
|
-
field_desc = original_field_info.description if original_field_info else ""
|
345
|
-
pydantic_fields[k] = (
|
346
|
-
type(v_instance),
|
347
|
-
Field(default=v_instance, description=field_desc),
|
348
|
-
)
|
349
|
-
|
350
|
-
new_model_class = create_model(model_name, __doc__=model_doc, **pydantic_fields)
|
351
|
-
return new_model_class(**instance_data)
|
352
|
-
|
353
|
-
|
354
|
-
# ITS OVER 9000
|
355
|
-
|
356
|
-
|
357
|
-
@overload
|
358
|
-
def convert_to_pydantic_model(
|
359
|
-
target: Type[BaseModelType],
|
360
|
-
init: Literal[False] = False,
|
361
|
-
name: Optional[str] = None,
|
362
|
-
description: Optional[str] = None,
|
363
|
-
field_name: Optional[str] = None,
|
364
|
-
default: Any = ...,
|
365
|
-
) -> Type[BaseModelType]: ...
|
366
|
-
@overload
|
367
|
-
def convert_to_pydantic_model(
|
368
|
-
target: Type[BaseModelType],
|
369
|
-
init: Literal[True],
|
370
|
-
name: Optional[str] = None,
|
371
|
-
description: Optional[str] = None,
|
372
|
-
field_name: Optional[str] = None,
|
373
|
-
default: Any = ...,
|
374
|
-
) -> BaseModelType: ...
|
375
|
-
@overload
|
376
|
-
def convert_to_pydantic_model(
|
377
|
-
target: BaseModelType,
|
378
|
-
init: Literal[False] = False,
|
379
|
-
name: Optional[str] = None,
|
380
|
-
description: Optional[str] = None,
|
381
|
-
field_name: Optional[str] = None,
|
382
|
-
default: Any = ...,
|
383
|
-
) -> Type[BaseModelType]: ...
|
384
|
-
@overload
|
385
|
-
def convert_to_pydantic_model(
|
386
|
-
target: BaseModelType,
|
387
|
-
init: Literal[True],
|
388
|
-
name: Optional[str] = None,
|
389
|
-
description: Optional[str] = None,
|
390
|
-
field_name: Optional[str] = None,
|
391
|
-
default: Any = ...,
|
392
|
-
) -> BaseModelType: ...
|
393
|
-
@overload
|
394
|
-
def convert_to_pydantic_model(
|
395
|
-
target: Type,
|
396
|
-
init: Literal[False] = False,
|
397
|
-
name: Optional[str] = None,
|
398
|
-
description: Optional[str] = None,
|
399
|
-
field_name: Optional[str] = None,
|
400
|
-
default: Any = ...,
|
401
|
-
) -> Type[BaseModel]: ...
|
402
|
-
@overload
|
403
|
-
def convert_to_pydantic_model(
|
404
|
-
target: Type,
|
405
|
-
init: Literal[True],
|
406
|
-
name: Optional[str] = None,
|
407
|
-
description: Optional[str] = None,
|
408
|
-
field_name: Optional[str] = None,
|
409
|
-
default: Any = ...,
|
410
|
-
) -> BaseModel: # For dataclass instances from type
|
411
|
-
...
|
412
|
-
@overload
|
413
|
-
def convert_to_pydantic_model(
|
414
|
-
target: Callable,
|
415
|
-
init: Literal[False] = False,
|
416
|
-
name: Optional[str] = None,
|
417
|
-
description: Optional[str] = None,
|
418
|
-
field_name: Optional[str] = None,
|
419
|
-
default: Any = ...,
|
420
|
-
) -> Type[BaseModel]: ...
|
421
|
-
@overload
|
422
|
-
def convert_to_pydantic_model(
|
423
|
-
target: Sequence[Type],
|
424
|
-
init: Literal[False] = False,
|
425
|
-
name: Optional[str] = None,
|
426
|
-
description: Optional[str] = None,
|
427
|
-
field_name: Optional[str] = None,
|
428
|
-
default: Any = ...,
|
429
|
-
) -> Type[BaseModel]: ...
|
430
|
-
@overload
|
431
|
-
def convert_to_pydantic_model(
|
432
|
-
target: Dict[str, Any],
|
433
|
-
init: Literal[False] = False,
|
434
|
-
name: Optional[str] = None,
|
435
|
-
description: Optional[str] = None,
|
436
|
-
field_name: Optional[str] = None,
|
437
|
-
default: Any = ...,
|
438
|
-
) -> Type[BaseModel]: ...
|
439
|
-
@overload
|
440
|
-
def convert_to_pydantic_model(
|
441
|
-
target: Dict[str, Any],
|
442
|
-
init: Literal[True],
|
443
|
-
name: Optional[str] = None,
|
444
|
-
description: Optional[str] = None,
|
445
|
-
field_name: Optional[str] = None,
|
446
|
-
default: Any = ...,
|
447
|
-
) -> BaseModel: ...
|
448
|
-
|
449
|
-
|
450
|
-
def convert_to_pydantic_model(
|
451
|
-
target: Union[Type, Sequence[Type], Dict[str, Any], BaseModel, Callable],
|
452
|
-
init: bool = False,
|
453
|
-
name: Optional[str] = None,
|
454
|
-
description: Optional[str] = None,
|
455
|
-
field_name: Optional[str] = None,
|
456
|
-
default: Any = ...,
|
457
|
-
) -> Union[Type[BaseModel], BaseModel]:
|
458
|
-
"""
|
459
|
-
Converts various input types into a Pydantic model class or instance.
|
460
|
-
|
461
|
-
Args:
|
462
|
-
target: The target to convert (Python type, Pydantic BaseModel class/instance,
|
463
|
-
dataclass type/instance, function, sequence of types, or dict).
|
464
|
-
init: If True, returns an initialized Pydantic model instance where applicable
|
465
|
-
(e.g., from a dict, dataclass instance, or BaseModel instance).
|
466
|
-
If False (default), returns a Pydantic model class.
|
467
|
-
name: Optional name for the generated Pydantic model.
|
468
|
-
description: Optional description for the model (used as its docstring).
|
469
|
-
field_name: Optional name for the primary field if `target` is a single type
|
470
|
-
or for the first field if `target` is a sequence of types.
|
471
|
-
default: Optional default value if `target` is a single type, used with `field_name`.
|
472
|
-
|
473
|
-
Returns:
|
474
|
-
A Pydantic model class, or an instance of one if `init` is True and applicable.
|
475
|
-
"""
|
476
|
-
# Handle existing Pydantic model classes
|
477
|
-
if is_pydantic_model_class(target):
|
478
|
-
target_cls = cast(Type[BaseModel], target)
|
479
|
-
if init:
|
480
|
-
try:
|
481
|
-
return target_cls()
|
482
|
-
except Exception as e:
|
483
|
-
logger.warning(
|
484
|
-
f"Cannot auto-initialize {target_cls.__name__} due to missing required fields: {e}"
|
485
|
-
)
|
486
|
-
# Cannot create instance without required fields, return the class instead
|
487
|
-
return target_cls
|
488
|
-
if name and name != target_cls.__name__ or description:
|
489
|
-
return _reconvert_to_pydantic_model_from_basemodel_instance(
|
490
|
-
target_cls(), name=name, description=description
|
491
|
-
)
|
492
|
-
return target_cls
|
493
|
-
|
494
|
-
# Handle Pydantic model instances
|
495
|
-
if isinstance(target, BaseModel):
|
496
|
-
if init:
|
497
|
-
return _reconvert_to_pydantic_model_from_basemodel_instance(
|
498
|
-
target, name=name, description=description
|
499
|
-
)
|
500
|
-
return target.__class__
|
501
|
-
|
502
|
-
# Handle dataclasses (types or instances)
|
503
|
-
if is_dataclass(target):
|
504
|
-
if isinstance(target, type):
|
505
|
-
# target is a dataclass type
|
506
|
-
return convert_dataclass_to_pydantic_model(
|
507
|
-
cast(Type, target),
|
508
|
-
init=init,
|
509
|
-
name=name,
|
510
|
-
description=description,
|
511
|
-
)
|
512
|
-
else:
|
513
|
-
# target is a dataclass instance
|
514
|
-
return convert_dataclass_to_pydantic_model(
|
515
|
-
target, # Pass the instance directly
|
516
|
-
init=init,
|
517
|
-
name=name,
|
518
|
-
description=description,
|
519
|
-
)
|
520
|
-
|
521
|
-
# Handle standard Python types (int, str, etc.)
|
522
|
-
if isinstance(target, type):
|
523
|
-
return convert_type_to_pydantic_model(
|
524
|
-
target, name, description, field_name, default
|
525
|
-
)
|
526
|
-
|
527
|
-
# Handle callables (functions)
|
528
|
-
if callable(target):
|
529
|
-
return convert_function_to_pydantic_model(target, name, description)
|
530
|
-
|
531
|
-
# Handle sequences of types
|
532
|
-
if isinstance(target, Sequence) and not isinstance(target, str):
|
533
|
-
if not all(isinstance(t, type) for t in target):
|
534
|
-
raise TypeError("If target is a sequence, all its elements must be types.")
|
535
|
-
return convert_sequence_to_pydantic_model(
|
536
|
-
cast(Sequence[Type], target), name, description, field_name, default
|
537
|
-
)
|
538
|
-
|
539
|
-
# Handle dictionaries
|
540
|
-
if isinstance(target, dict):
|
541
|
-
return convert_dict_to_pydantic_model(target, init, name, description)
|
542
|
-
|
543
|
-
else:
|
544
|
-
logger.error(
|
545
|
-
f"Unsupported target type for Pydantic model creation: {type(target)} | how did you get here?"
|
546
|
-
)
|
547
|
-
raise TypeError(
|
548
|
-
f"Cannot create Pydantic model from target of type {type(target)}"
|
549
|
-
)
|
550
|
-
|
551
|
-
|
552
|
-
# -----------------------------------------------------------------------------
|
553
|
-
# Specialized Model Creation Utils
|
554
|
-
# -----------------------------------------------------------------------------
|
555
|
-
|
556
|
-
|
557
|
-
@cached
|
558
|
-
def create_selection_pydantic_model(
|
559
|
-
fields: List[str],
|
560
|
-
name: str = "Selection",
|
561
|
-
description: Optional[str] = None,
|
562
|
-
) -> Type[BaseModel]:
|
563
|
-
"""
|
564
|
-
Creates a Pydantic model for making a selection from a list of string options.
|
565
|
-
The model will have a single field named `selection` of type `Literal[*fields]`.
|
566
|
-
|
567
|
-
Args:
|
568
|
-
fields: A list of strings representing the allowed choices. Must not be empty.
|
569
|
-
name: The name for the created Pydantic model.
|
570
|
-
description: Optional description for the model (becomes its docstring).
|
571
|
-
|
572
|
-
Returns:
|
573
|
-
A new Pydantic BaseModel class with a 'selection' field.
|
574
|
-
Raises:
|
575
|
-
ValueError: If `fields` is empty.
|
576
|
-
"""
|
577
|
-
if not fields:
|
578
|
-
raise ValueError(
|
579
|
-
"`fields` list cannot be empty for `create_selection_pydantic_model`."
|
580
|
-
)
|
581
|
-
|
582
|
-
literal_args_str = ", ".join(repr(str(f)) for f in fields)
|
583
|
-
selection_type = eval(f"Literal[{literal_args_str}]")
|
584
|
-
|
585
|
-
model_fields_definitions = {
|
586
|
-
"selection": (
|
587
|
-
selection_type,
|
588
|
-
Field(..., description="The selected value from the available options."),
|
589
|
-
)
|
590
|
-
}
|
591
|
-
model_docstring = (
|
592
|
-
description or f"A model for selecting one option from: {', '.join(fields)}."
|
593
|
-
)
|
594
|
-
return create_model(
|
595
|
-
name, __base__=BaseModel, __doc__=model_docstring, **model_fields_definitions
|
596
|
-
)
|
597
|
-
|
598
|
-
|
599
|
-
@cached
|
600
|
-
def create_confirmation_pydantic_model(
|
601
|
-
name: str = "Confirmation",
|
602
|
-
description: Optional[str] = None,
|
603
|
-
field_name: str = "confirmed",
|
604
|
-
) -> Type[BaseModel]:
|
605
|
-
"""
|
606
|
-
Creates a Pydantic model for a boolean confirmation.
|
607
|
-
The model will have a single boolean field.
|
608
|
-
|
609
|
-
Args:
|
610
|
-
name: The name for the created Pydantic model.
|
611
|
-
description: Optional description for the model.
|
612
|
-
field_name: Name of the boolean field in the model.
|
613
|
-
|
614
|
-
Returns:
|
615
|
-
A new Pydantic BaseModel class.
|
616
|
-
"""
|
617
|
-
model_fields_definitions = {
|
618
|
-
field_name: (bool, Field(..., description="The boolean confirmation value."))
|
619
|
-
}
|
620
|
-
model_docstring = description or "A model for boolean confirmation."
|
621
|
-
return create_model(
|
622
|
-
name, __base__=BaseModel, __doc__=model_docstring, **model_fields_definitions
|
623
|
-
)
|
@@ -1,28 +0,0 @@
|
|
1
|
-
"""hammad.pydantic.models"""
|
2
|
-
|
3
|
-
from typing import TYPE_CHECKING
|
4
|
-
from ..._core._utils._import_utils import _auto_create_getattr_loader
|
5
|
-
|
6
|
-
if TYPE_CHECKING:
|
7
|
-
from .arbitrary_model import ArbitraryModel
|
8
|
-
from .cacheable_model import CacheableModel
|
9
|
-
from .fast_model import FastModel
|
10
|
-
from .function_model import FunctionModel
|
11
|
-
from .subscriptable_model import SubscriptableModel
|
12
|
-
|
13
|
-
|
14
|
-
__all__ = (
|
15
|
-
"ArbitraryModel",
|
16
|
-
"CacheableModel",
|
17
|
-
"FastModel",
|
18
|
-
"FunctionModel",
|
19
|
-
"SubscriptableModel",
|
20
|
-
)
|
21
|
-
|
22
|
-
|
23
|
-
__getattr__ = _auto_create_getattr_loader(__all__)
|
24
|
-
|
25
|
-
|
26
|
-
def __dir__() -> list[str]:
|
27
|
-
"""Get the attributes of the models module."""
|
28
|
-
return list(__all__)
|
@@ -1,46 +0,0 @@
|
|
1
|
-
"""hammad.pydantic.models.arbitrary_model"""
|
2
|
-
|
3
|
-
from typing import Any, Dict
|
4
|
-
from pydantic import ConfigDict
|
5
|
-
|
6
|
-
from .subscriptable_model import SubscriptableModel
|
7
|
-
|
8
|
-
__all__ = ("ArbitraryModel",)
|
9
|
-
|
10
|
-
|
11
|
-
class ArbitraryModel(SubscriptableModel):
|
12
|
-
"""
|
13
|
-
A model that allows dynamic field assignment and access.
|
14
|
-
Perfect for handling arbitrary JSON data or when schema is unknown at compile time.
|
15
|
-
|
16
|
-
Usage:
|
17
|
-
>>> data = ArbitraryModel()
|
18
|
-
>>> data.name = "John"
|
19
|
-
>>> data.age = 30
|
20
|
-
>>> data.metadata = {"key": "value"}
|
21
|
-
>>> print(data.name) # John
|
22
|
-
>>> print(data["age"]) # 30
|
23
|
-
"""
|
24
|
-
|
25
|
-
model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True)
|
26
|
-
|
27
|
-
def __init__(self, **data: Any):
|
28
|
-
super().__init__(**data)
|
29
|
-
# Store extra fields for easy access
|
30
|
-
self._arbitrary_fields: Dict[str, Any] = {}
|
31
|
-
|
32
|
-
def __setattr__(self, name: str, value: Any) -> None:
|
33
|
-
if name.startswith("_") or name in self.__class__.model_fields:
|
34
|
-
super().__setattr__(name, value)
|
35
|
-
else:
|
36
|
-
# Store in dynamic fields and set normally
|
37
|
-
if hasattr(self, "_arbitrary_fields"):
|
38
|
-
self._arbitrary_fields[name] = value
|
39
|
-
super().__setattr__(name, value)
|
40
|
-
|
41
|
-
def to_dict(self) -> Dict[str, Any]:
|
42
|
-
"""Convert to dictionary including all dynamic fields."""
|
43
|
-
result = self.model_dump()
|
44
|
-
if hasattr(self, "_arbitrary_fields"):
|
45
|
-
result.update(self._arbitrary_fields)
|
46
|
-
return result
|