hammad-python 0.0.29__py3-none-any.whl → 0.0.31__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 (137) hide show
  1. ham/__init__.py +10 -0
  2. {hammad_python-0.0.29.dist-info → hammad_python-0.0.31.dist-info}/METADATA +6 -32
  3. hammad_python-0.0.31.dist-info/RECORD +6 -0
  4. hammad/__init__.py +0 -84
  5. hammad/_internal.py +0 -256
  6. hammad/_main.py +0 -226
  7. hammad/cache/__init__.py +0 -40
  8. hammad/cache/base_cache.py +0 -181
  9. hammad/cache/cache.py +0 -169
  10. hammad/cache/decorators.py +0 -261
  11. hammad/cache/file_cache.py +0 -80
  12. hammad/cache/ttl_cache.py +0 -74
  13. hammad/cli/__init__.py +0 -33
  14. hammad/cli/animations.py +0 -573
  15. hammad/cli/plugins.py +0 -867
  16. hammad/cli/styles/__init__.py +0 -55
  17. hammad/cli/styles/settings.py +0 -139
  18. hammad/cli/styles/types.py +0 -358
  19. hammad/cli/styles/utils.py +0 -634
  20. hammad/data/__init__.py +0 -90
  21. hammad/data/collections/__init__.py +0 -49
  22. hammad/data/collections/collection.py +0 -326
  23. hammad/data/collections/indexes/__init__.py +0 -37
  24. hammad/data/collections/indexes/qdrant/__init__.py +0 -1
  25. hammad/data/collections/indexes/qdrant/index.py +0 -723
  26. hammad/data/collections/indexes/qdrant/settings.py +0 -94
  27. hammad/data/collections/indexes/qdrant/utils.py +0 -210
  28. hammad/data/collections/indexes/tantivy/__init__.py +0 -1
  29. hammad/data/collections/indexes/tantivy/index.py +0 -426
  30. hammad/data/collections/indexes/tantivy/settings.py +0 -40
  31. hammad/data/collections/indexes/tantivy/utils.py +0 -176
  32. hammad/data/configurations/__init__.py +0 -35
  33. hammad/data/configurations/configuration.py +0 -564
  34. hammad/data/models/__init__.py +0 -50
  35. hammad/data/models/extensions/__init__.py +0 -4
  36. hammad/data/models/extensions/pydantic/__init__.py +0 -42
  37. hammad/data/models/extensions/pydantic/converters.py +0 -759
  38. hammad/data/models/fields.py +0 -546
  39. hammad/data/models/model.py +0 -1078
  40. hammad/data/models/utils.py +0 -280
  41. hammad/data/sql/__init__.py +0 -24
  42. hammad/data/sql/database.py +0 -576
  43. hammad/data/sql/types.py +0 -127
  44. hammad/data/types/__init__.py +0 -75
  45. hammad/data/types/file.py +0 -431
  46. hammad/data/types/multimodal/__init__.py +0 -36
  47. hammad/data/types/multimodal/audio.py +0 -200
  48. hammad/data/types/multimodal/image.py +0 -182
  49. hammad/data/types/text.py +0 -1308
  50. hammad/formatting/__init__.py +0 -33
  51. hammad/formatting/json/__init__.py +0 -27
  52. hammad/formatting/json/converters.py +0 -158
  53. hammad/formatting/text/__init__.py +0 -63
  54. hammad/formatting/text/converters.py +0 -723
  55. hammad/formatting/text/markdown.py +0 -131
  56. hammad/formatting/yaml/__init__.py +0 -26
  57. hammad/formatting/yaml/converters.py +0 -5
  58. hammad/genai/__init__.py +0 -217
  59. hammad/genai/a2a/__init__.py +0 -32
  60. hammad/genai/a2a/workers.py +0 -552
  61. hammad/genai/agents/__init__.py +0 -59
  62. hammad/genai/agents/agent.py +0 -1973
  63. hammad/genai/agents/run.py +0 -1024
  64. hammad/genai/agents/types/__init__.py +0 -42
  65. hammad/genai/agents/types/agent_context.py +0 -13
  66. hammad/genai/agents/types/agent_event.py +0 -128
  67. hammad/genai/agents/types/agent_hooks.py +0 -220
  68. hammad/genai/agents/types/agent_messages.py +0 -31
  69. hammad/genai/agents/types/agent_response.py +0 -125
  70. hammad/genai/agents/types/agent_stream.py +0 -327
  71. hammad/genai/graphs/__init__.py +0 -125
  72. hammad/genai/graphs/_utils.py +0 -190
  73. hammad/genai/graphs/base.py +0 -1828
  74. hammad/genai/graphs/plugins.py +0 -316
  75. hammad/genai/graphs/types.py +0 -638
  76. hammad/genai/models/__init__.py +0 -1
  77. hammad/genai/models/embeddings/__init__.py +0 -43
  78. hammad/genai/models/embeddings/model.py +0 -226
  79. hammad/genai/models/embeddings/run.py +0 -163
  80. hammad/genai/models/embeddings/types/__init__.py +0 -37
  81. hammad/genai/models/embeddings/types/embedding_model_name.py +0 -75
  82. hammad/genai/models/embeddings/types/embedding_model_response.py +0 -76
  83. hammad/genai/models/embeddings/types/embedding_model_run_params.py +0 -66
  84. hammad/genai/models/embeddings/types/embedding_model_settings.py +0 -47
  85. hammad/genai/models/language/__init__.py +0 -57
  86. hammad/genai/models/language/model.py +0 -1098
  87. hammad/genai/models/language/run.py +0 -878
  88. hammad/genai/models/language/types/__init__.py +0 -40
  89. hammad/genai/models/language/types/language_model_instructor_mode.py +0 -47
  90. hammad/genai/models/language/types/language_model_messages.py +0 -28
  91. hammad/genai/models/language/types/language_model_name.py +0 -239
  92. hammad/genai/models/language/types/language_model_request.py +0 -127
  93. hammad/genai/models/language/types/language_model_response.py +0 -217
  94. hammad/genai/models/language/types/language_model_response_chunk.py +0 -56
  95. hammad/genai/models/language/types/language_model_settings.py +0 -89
  96. hammad/genai/models/language/types/language_model_stream.py +0 -600
  97. hammad/genai/models/language/utils/__init__.py +0 -28
  98. hammad/genai/models/language/utils/requests.py +0 -421
  99. hammad/genai/models/language/utils/structured_outputs.py +0 -135
  100. hammad/genai/models/model_provider.py +0 -4
  101. hammad/genai/models/multimodal.py +0 -47
  102. hammad/genai/models/reranking.py +0 -26
  103. hammad/genai/types/__init__.py +0 -1
  104. hammad/genai/types/base.py +0 -215
  105. hammad/genai/types/history.py +0 -290
  106. hammad/genai/types/tools.py +0 -507
  107. hammad/logging/__init__.py +0 -35
  108. hammad/logging/decorators.py +0 -834
  109. hammad/logging/logger.py +0 -1018
  110. hammad/mcp/__init__.py +0 -53
  111. hammad/mcp/client/__init__.py +0 -35
  112. hammad/mcp/client/client.py +0 -624
  113. hammad/mcp/client/client_service.py +0 -400
  114. hammad/mcp/client/settings.py +0 -178
  115. hammad/mcp/servers/__init__.py +0 -26
  116. hammad/mcp/servers/launcher.py +0 -1161
  117. hammad/runtime/__init__.py +0 -32
  118. hammad/runtime/decorators.py +0 -142
  119. hammad/runtime/run.py +0 -299
  120. hammad/service/__init__.py +0 -49
  121. hammad/service/create.py +0 -527
  122. hammad/service/decorators.py +0 -283
  123. hammad/types.py +0 -288
  124. hammad/typing/__init__.py +0 -435
  125. hammad/web/__init__.py +0 -43
  126. hammad/web/http/__init__.py +0 -1
  127. hammad/web/http/client.py +0 -944
  128. hammad/web/models.py +0 -275
  129. hammad/web/openapi/__init__.py +0 -1
  130. hammad/web/openapi/client.py +0 -740
  131. hammad/web/search/__init__.py +0 -1
  132. hammad/web/search/client.py +0 -1023
  133. hammad/web/utils.py +0 -472
  134. hammad_python-0.0.29.dist-info/RECORD +0 -135
  135. {hammad → ham}/py.typed +0 -0
  136. {hammad_python-0.0.29.dist-info → hammad_python-0.0.31.dist-info}/WHEEL +0 -0
  137. {hammad_python-0.0.29.dist-info → hammad_python-0.0.31.dist-info}/licenses/LICENSE +0 -0
@@ -1,759 +0,0 @@
1
- """hammad.data.models.extensions.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 typing import get_origin, get_args
32
- from typing_inspect import is_generic_type
33
-
34
- logger = logging.getLogger(__name__)
35
-
36
- __all__ = [
37
- "is_pydantic_model_class",
38
- "get_pydantic_fields_from_function",
39
- "convert_to_pydantic_field",
40
- "convert_to_pydantic_model",
41
- "create_selection_pydantic_model",
42
- "create_confirmation_pydantic_model",
43
- "convert_dataclass_to_pydantic_model",
44
- "convert_type_to_pydantic_model",
45
- "convert_function_to_pydantic_model",
46
- "convert_sequence_to_pydantic_model",
47
- "convert_dict_to_pydantic_model",
48
- ]
49
-
50
-
51
- # -----------------------------------------------------------------------------
52
- # Types & Constants
53
- # -----------------------------------------------------------------------------
54
-
55
- BaseModelType = TypeVar("BaseModelType", bound=BaseModel)
56
- """Helper type for Pydantic model classes."""
57
-
58
-
59
- JSON_TYPE_MAPPING: Mapping[Any, Tuple[str, Any]] = {
60
- int: ("int", int),
61
- float: ("float", float),
62
- bool: ("bool", bool),
63
- str: ("str", str),
64
- bytes: ("bytes", bytes),
65
- list: ("list", list),
66
- tuple: ("tuple", tuple),
67
- dict: ("dict", dict),
68
- set: ("set", set),
69
- frozenset: ("frozenset", frozenset),
70
- Any: ("any", Any),
71
- None: ("none", None),
72
- Union: ("union", Union),
73
- Optional: ("optional", Optional),
74
- }
75
- """
76
- A mapping of types to their string representations. Used for hinting & JSON schema
77
- generation.
78
- """
79
-
80
- TYPE_NAME_MAPPING: Dict[Type, str] = {
81
- int: "Integer",
82
- float: "Float",
83
- bool: "Boolean",
84
- str: "String",
85
- bytes: "Bytes",
86
- list: "List",
87
- tuple: "Tuple",
88
- dict: "Dict",
89
- set: "Set",
90
- frozenset: "FrozenSet",
91
- }
92
- """
93
- A mapping of basic types to their semantic model names.
94
- """
95
-
96
- FIELD_NAME_MAPPING: Dict[Type, str] = {
97
- int: "value",
98
- float: "value",
99
- bool: "flag",
100
- str: "text",
101
- bytes: "data",
102
- list: "items",
103
- tuple: "values",
104
- dict: "mapping",
105
- set: "elements",
106
- frozenset: "elements",
107
- }
108
- """
109
- A mapping of basic types to their semantic field names.
110
- """
111
-
112
-
113
- # -----------------------------------------------------------------------------
114
- # Pydantic Model Utils
115
- # -----------------------------------------------------------------------------
116
-
117
-
118
- def is_pydantic_model_class(obj: Any) -> bool:
119
- """
120
- Checks if an object is a Pydantic model class.
121
- """
122
- return isinstance(obj, type) and issubclass(obj, BaseModel)
123
-
124
-
125
- def generate_semantic_model_name(type_hint: Type) -> str:
126
- """
127
- Generates a semantic model name based on the type.
128
-
129
- Examples:
130
- int -> "Integer"
131
- str -> "String"
132
- List[int] -> "IntegerList"
133
- Dict[str, int] -> "StringIntegerDict"
134
- Optional[int] -> "OptionalInteger"
135
- Union[str, int] -> "StringIntegerUnion"
136
- """
137
- # Handle basic types
138
- if type_hint in TYPE_NAME_MAPPING:
139
- return TYPE_NAME_MAPPING[type_hint]
140
-
141
- # Handle Optional types
142
- origin = get_origin(type_hint)
143
- args = get_args(type_hint)
144
-
145
- if origin is Union:
146
- # Check if it's Optional (Union with None)
147
- if type(None) in args and len(args) == 2:
148
- # This is Optional[T]
149
- inner_type = next(arg for arg in args if arg is not type(None))
150
- return f"Optional{generate_semantic_model_name(inner_type)}"
151
- else:
152
- # Regular Union
153
- type_names = [
154
- generate_semantic_model_name(arg)
155
- for arg in args
156
- if arg is not type(None)
157
- ]
158
- return "".join(type_names) + "Union"
159
-
160
- # Handle generic types
161
- if origin is not None:
162
- origin_name = TYPE_NAME_MAPPING.get(origin, origin.__name__.capitalize())
163
-
164
- if args:
165
- # Generate names for type arguments
166
- arg_names = [generate_semantic_model_name(arg) for arg in args]
167
- if origin in (list, set, frozenset):
168
- # For collections, append the element type
169
- return f"{arg_names[0]}{origin_name}"
170
- elif origin is dict:
171
- # For dict, include both key and value types
172
- return f"{arg_names[0]}{arg_names[1]}Dict"
173
- elif origin is tuple:
174
- # For tuple, join all types
175
- return "".join(arg_names) + "Tuple"
176
- else:
177
- # For other generics, prepend type arguments
178
- return "".join(arg_names) + origin_name
179
-
180
- return origin_name
181
-
182
- # Fallback to the type's name
183
- if hasattr(type_hint, "__name__"):
184
- return type_hint.__name__.capitalize()
185
-
186
- return "GeneratedModel"
187
-
188
-
189
- def generate_semantic_field_name(type_hint: Type) -> str:
190
- """
191
- Generates a semantic field name based on the type.
192
-
193
- Examples:
194
- int -> "value"
195
- str -> "text"
196
- List[int] -> "items"
197
- Dict[str, int] -> "mapping"
198
- Optional[str] -> "text"
199
- """
200
- # Handle basic types
201
- if type_hint in FIELD_NAME_MAPPING:
202
- return FIELD_NAME_MAPPING[type_hint]
203
-
204
- # Handle Optional types - use the inner type's field name
205
- origin = get_origin(type_hint)
206
- args = get_args(type_hint)
207
-
208
- if origin is Union:
209
- # Check if it's Optional (Union with None)
210
- if type(None) in args and len(args) == 2:
211
- # This is Optional[T] - use inner type's field name
212
- inner_type = next(arg for arg in args if arg is not type(None))
213
- return generate_semantic_field_name(inner_type)
214
-
215
- # Handle generic types - use the origin's field name
216
- if origin is not None and origin in FIELD_NAME_MAPPING:
217
- return FIELD_NAME_MAPPING[origin]
218
-
219
- # Default fallback
220
- return "value"
221
-
222
-
223
- def get_pydantic_fields_from_function(func: Callable) -> Dict[str, Tuple[Type, Field]]:
224
- """
225
- Extracts Pydantic fields from a function's signature and docstring.
226
- Returns a dictionary mapping field names to (type, Pydantic Field) tuples.
227
-
228
- Args:
229
- func: The function to extract Pydantic fields from.
230
-
231
- Returns:
232
- A dictionary mapping field names to (type, Pydantic Field) tuples.
233
- """
234
- try:
235
- hints = get_type_hints(func)
236
- fields_dict: Dict[str, Tuple[Type, Field]] = {}
237
- doc_info = parse(func.__doc__ or "")
238
-
239
- for param_name, param_type in hints.items():
240
- if param_name == "return":
241
- continue
242
-
243
- description = ""
244
- if doc_info.params:
245
- description = (
246
- next(
247
- (
248
- p.description
249
- for p in doc_info.params
250
- if p.arg_name == param_name
251
- ),
252
- "",
253
- )
254
- or ""
255
- )
256
-
257
- default_value = ...
258
- param = inspect.signature(func).parameters.get(param_name)
259
- if param and param.default is not inspect.Parameter.empty:
260
- default_value = param.default
261
-
262
- fields_dict[param_name] = (
263
- param_type,
264
- Field(default=default_value, description=description),
265
- )
266
- return fields_dict
267
- except Exception as e:
268
- logger.error(
269
- f"Error extracting function fields for {getattr(func, '__name__', 'unknown function')}: {e}"
270
- )
271
- return {}
272
-
273
-
274
- def convert_to_pydantic_field(
275
- type_hint: Type,
276
- index: Optional[int] = None,
277
- description: Optional[str] = None,
278
- default: Any = ...,
279
- ) -> Dict[str, Tuple[Type, Field]]:
280
- """
281
- Creates a Pydantic field definition from a type hint.
282
- Returns a dictionary mapping a generated field name to its (type, Field) tuple.
283
- """
284
- try:
285
- # Use semantic field name if no index is provided
286
- if index is None:
287
- field_name = generate_semantic_field_name(type_hint)
288
- else:
289
- # Use indexed field name for sequences
290
- base_name = generate_semantic_field_name(type_hint)
291
- field_name = f"{base_name}_{index}"
292
-
293
- return {
294
- field_name: (
295
- type_hint,
296
- Field(default=default, description=description or ""),
297
- )
298
- }
299
- except Exception as e:
300
- logger.error(f"Error creating Pydantic field mapping for type {type_hint}: {e}")
301
- raise
302
-
303
-
304
- # -----------------------------------------------------------------------------
305
- # Simplified Model Creation
306
- # -----------------------------------------------------------------------------
307
-
308
-
309
- # -----------------------------------------------------------------------------
310
- # Helpers (Private)
311
- # -----------------------------------------------------------------------------
312
-
313
-
314
- def convert_dataclass_to_pydantic_model(
315
- target: Union[Type, Any], # NOTE: DATACLASS TYPE OR INSTANCE
316
- init: bool,
317
- name: Optional[str],
318
- description: Optional[str],
319
- ) -> Union[Type[BaseModel], BaseModel]:
320
- # Determine if we're dealing with a type or instance
321
- is_instance = not isinstance(target, type)
322
- dataclass_type = type(target) if is_instance else target
323
-
324
- model_name = name or dataclass_type.__name__
325
- doc_info = parse(dataclass_type.__doc__ or "")
326
- model_doc = description or doc_info.short_description
327
-
328
- pydantic_fields: Dict[str, Tuple[Type, Field]] = {}
329
- for dc_field in dataclass_fields(dataclass_type):
330
- field_type = dc_field.type
331
- field_default = dc_field.default if dc_field.default is not MISSING else ... # type: ignore
332
- if dc_field.default_factory is not MISSING: # type: ignore
333
- field_default = Field(default_factory=dc_field.default_factory)
334
-
335
- field_description = ""
336
- if doc_info.params:
337
- field_description = (
338
- next(
339
- (
340
- p.description
341
- for p in doc_info.params
342
- if p.arg_name == dc_field.name
343
- ),
344
- "",
345
- )
346
- or ""
347
- )
348
-
349
- pydantic_fields[dc_field.name] = (
350
- field_type,
351
- Field(default=field_default, description=field_description),
352
- )
353
-
354
- model_class = create_model(model_name, __doc__=model_doc, **pydantic_fields)
355
-
356
- if init and is_instance:
357
- instance_data = {
358
- f.name: getattr(target, f.name) for f in dataclass_fields(dataclass_type)
359
- }
360
- return model_class(**instance_data)
361
- return model_class
362
-
363
-
364
- def convert_type_to_pydantic_model(
365
- target: Type,
366
- name: Optional[str],
367
- description: Optional[str],
368
- field_name: Optional[str],
369
- default: Any,
370
- ) -> Type[BaseModel]:
371
- # Use semantic naming if no name is provided
372
- model_name = name or generate_semantic_model_name(target)
373
-
374
- field_mapping = convert_to_pydantic_field(
375
- target, description=description, default=default
376
- )
377
-
378
- if field_name: # Override default field name if explicitly provided
379
- current_field_def = list(field_mapping.values())[0]
380
- field_mapping = {field_name: current_field_def}
381
-
382
- return create_model(model_name, __doc__=(description or ""), **field_mapping)
383
-
384
-
385
- def convert_function_to_pydantic_model(
386
- target: Callable,
387
- name: Optional[str],
388
- description: Optional[str],
389
- ) -> Type[BaseModel]:
390
- model_name = name or target.__name__
391
- doc_info = parse(target.__doc__ or "")
392
- model_doc = description or doc_info.short_description
393
-
394
- fields = get_pydantic_fields_from_function(target)
395
- return create_model(model_name, __doc__=model_doc, **fields)
396
-
397
-
398
- def convert_sequence_to_pydantic_model(
399
- target: Sequence[Type],
400
- name: Optional[str],
401
- description: Optional[str],
402
- field_name: Optional[str],
403
- default: Any,
404
- ) -> Type[BaseModel]:
405
- if not target:
406
- raise ValueError("Cannot create Pydantic model from empty sequence")
407
-
408
- model_name = name or "GeneratedModel"
409
- pydantic_fields: Dict[str, Tuple[Type, Field]] = {}
410
-
411
- for i, type_hint in enumerate(target):
412
- if not isinstance(type_hint, type):
413
- raise ValueError(
414
- f"Sequence elements must be types, got {type_hint} at index {i}"
415
- )
416
-
417
- field_desc = description if i == 0 and field_name else None
418
- field_def_default = default if i == 0 and field_name else ...
419
-
420
- # Use provided field_name for the first element if specified
421
- current_field_name_override = field_name if i == 0 else None
422
-
423
- # Generate field(s) from type_hint
424
- temp_field_def = convert_to_pydantic_field(
425
- type_hint,
426
- index=None if current_field_name_override else i,
427
- description=field_desc,
428
- default=field_def_default,
429
- )
430
-
431
- actual_field_name = list(temp_field_def.keys())[0]
432
- actual_type_info = list(temp_field_def.values())[0]
433
-
434
- if current_field_name_override:
435
- pydantic_fields[current_field_name_override] = actual_type_info
436
- else:
437
- pydantic_fields[actual_field_name] = actual_type_info
438
-
439
- return create_model(model_name, __doc__=(description or ""), **pydantic_fields)
440
-
441
-
442
- def convert_dict_to_pydantic_model(
443
- target: Dict[str, Any],
444
- init: bool,
445
- name: Optional[str],
446
- description: Optional[str],
447
- ) -> Union[Type[BaseModel], BaseModel]:
448
- model_name = name or "GeneratedModel"
449
-
450
- pydantic_fields: Dict[str, Tuple[Type, Field]] = {}
451
- for k, v in target.items():
452
- pydantic_fields[k] = (type(v), Field(default=v if init else ...))
453
-
454
- model_class = create_model(
455
- model_name, __doc__=(description or ""), **pydantic_fields
456
- )
457
-
458
- if init:
459
- return model_class(**target)
460
- return model_class
461
-
462
-
463
- def _reconvert_to_pydantic_model_from_basemodel_instance(
464
- target: BaseModel,
465
- name: Optional[str],
466
- description: Optional[str],
467
- ) -> BaseModel:
468
- model_name = name or target.__class__.__name__
469
- doc_info = parse(target.__class__.__doc__ or "")
470
- model_doc = description or doc_info.short_description
471
-
472
- instance_data = target.model_dump()
473
- pydantic_fields: Dict[str, Tuple[Type, Field]] = {}
474
- for k, v_instance in instance_data.items():
475
- original_field_info = target.__class__.model_fields.get(k)
476
- field_desc = original_field_info.description if original_field_info else ""
477
- pydantic_fields[k] = (
478
- type(v_instance),
479
- Field(default=v_instance, description=field_desc),
480
- )
481
-
482
- new_model_class = create_model(model_name, __doc__=model_doc, **pydantic_fields)
483
- return new_model_class(**instance_data)
484
-
485
-
486
- # ITS OVER 9000
487
-
488
-
489
- @overload
490
- def convert_to_pydantic_model(
491
- target: Type[BaseModelType],
492
- init: Literal[False] = False,
493
- name: Optional[str] = None,
494
- description: Optional[str] = None,
495
- field_name: Optional[str] = None,
496
- default: Any = ...,
497
- ) -> Type[BaseModelType]: ...
498
- @overload
499
- def convert_to_pydantic_model(
500
- target: Type[BaseModelType],
501
- init: Literal[True],
502
- name: Optional[str] = None,
503
- description: Optional[str] = None,
504
- field_name: Optional[str] = None,
505
- default: Any = ...,
506
- ) -> BaseModelType: ...
507
- @overload
508
- def convert_to_pydantic_model(
509
- target: BaseModelType,
510
- init: Literal[False] = False,
511
- name: Optional[str] = None,
512
- description: Optional[str] = None,
513
- field_name: Optional[str] = None,
514
- default: Any = ...,
515
- ) -> Type[BaseModelType]: ...
516
- @overload
517
- def convert_to_pydantic_model(
518
- target: BaseModelType,
519
- init: Literal[True],
520
- name: Optional[str] = None,
521
- description: Optional[str] = None,
522
- field_name: Optional[str] = None,
523
- default: Any = ...,
524
- ) -> BaseModelType: ...
525
- @overload
526
- def convert_to_pydantic_model(
527
- target: Type,
528
- init: Literal[False] = False,
529
- name: Optional[str] = None,
530
- description: Optional[str] = None,
531
- field_name: Optional[str] = None,
532
- default: Any = ...,
533
- ) -> Type[BaseModel]: ...
534
- @overload
535
- def convert_to_pydantic_model(
536
- target: Type,
537
- init: Literal[True],
538
- name: Optional[str] = None,
539
- description: Optional[str] = None,
540
- field_name: Optional[str] = None,
541
- default: Any = ...,
542
- ) -> BaseModel: # For dataclass instances from type
543
- ...
544
- @overload
545
- def convert_to_pydantic_model(
546
- target: Callable,
547
- init: Literal[False] = False,
548
- name: Optional[str] = None,
549
- description: Optional[str] = None,
550
- field_name: Optional[str] = None,
551
- default: Any = ...,
552
- ) -> Type[BaseModel]: ...
553
- @overload
554
- def convert_to_pydantic_model(
555
- target: Sequence[Type],
556
- init: Literal[False] = False,
557
- name: Optional[str] = None,
558
- description: Optional[str] = None,
559
- field_name: Optional[str] = None,
560
- default: Any = ...,
561
- ) -> Type[BaseModel]: ...
562
- @overload
563
- def convert_to_pydantic_model(
564
- target: Dict[str, Any],
565
- init: Literal[False] = False,
566
- name: Optional[str] = None,
567
- description: Optional[str] = None,
568
- field_name: Optional[str] = None,
569
- default: Any = ...,
570
- ) -> Type[BaseModel]: ...
571
- @overload
572
- def convert_to_pydantic_model(
573
- target: Dict[str, Any],
574
- init: Literal[True],
575
- name: Optional[str] = None,
576
- description: Optional[str] = None,
577
- field_name: Optional[str] = None,
578
- default: Any = ...,
579
- ) -> BaseModel: ...
580
-
581
-
582
- def convert_to_pydantic_model(
583
- target: Union[Type, Sequence[Type], Dict[str, Any], BaseModel, Callable],
584
- init: bool = False,
585
- name: Optional[str] = None,
586
- description: Optional[str] = None,
587
- field_name: Optional[str] = None,
588
- default: Any = ...,
589
- ) -> Union[Type[BaseModel], BaseModel]:
590
- """
591
- Converts various input types into a Pydantic model class or instance.
592
-
593
- Args:
594
- target: The target to convert (Python type, Pydantic BaseModel class/instance,
595
- dataclass type/instance, function, sequence of types, or dict).
596
- init: If True, returns an initialized Pydantic model instance where applicable
597
- (e.g., from a dict, dataclass instance, or BaseModel instance).
598
- If False (default), returns a Pydantic model class.
599
- name: Optional name for the generated Pydantic model.
600
- description: Optional description for the model (used as its docstring).
601
- field_name: Optional name for the primary field if `target` is a single type
602
- or for the first field if `target` is a sequence of types.
603
- default: Optional default value if `target` is a single type, used with `field_name`.
604
-
605
- Returns:
606
- A Pydantic model class, or an instance of one if `init` is True and applicable.
607
- """
608
- # Handle existing Pydantic model classes
609
- if is_pydantic_model_class(target):
610
- target_cls = cast(Type[BaseModel], target)
611
- if init:
612
- try:
613
- return target_cls()
614
- except Exception as e:
615
- logger.warning(
616
- f"Cannot auto-initialize {target_cls.__name__} due to missing required fields: {e}"
617
- )
618
- # Cannot create instance without required fields, return the class instead
619
- return target_cls
620
- if name and name != target_cls.__name__ or description:
621
- return _reconvert_to_pydantic_model_from_basemodel_instance(
622
- target_cls(), name=name, description=description
623
- )
624
- return target_cls
625
-
626
- # Handle Pydantic model instances
627
- if isinstance(target, BaseModel):
628
- if init:
629
- return _reconvert_to_pydantic_model_from_basemodel_instance(
630
- target, name=name, description=description
631
- )
632
- return target.__class__
633
-
634
- # Handle dataclasses (types or instances)
635
- if is_dataclass(target):
636
- if isinstance(target, type):
637
- # target is a dataclass type
638
- return convert_dataclass_to_pydantic_model(
639
- cast(Type, target),
640
- init=init,
641
- name=name,
642
- description=description,
643
- )
644
- else:
645
- # target is a dataclass instance
646
- return convert_dataclass_to_pydantic_model(
647
- target, # Pass the instance directly
648
- init=init,
649
- name=name,
650
- description=description,
651
- )
652
-
653
- # Handle generic types (like list[str], dict[str, int], etc.)
654
- if is_generic_type(target) or get_origin(target) is not None:
655
- return convert_type_to_pydantic_model(
656
- target, name, description, field_name, default
657
- )
658
-
659
- # Handle standard Python types (int, str, etc.)
660
- if isinstance(target, type):
661
- return convert_type_to_pydantic_model(
662
- target, name, description, field_name, default
663
- )
664
-
665
- # Handle callables (functions)
666
- if callable(target):
667
- return convert_function_to_pydantic_model(target, name, description)
668
-
669
- # Handle sequences of types
670
- if isinstance(target, Sequence) and not isinstance(target, str):
671
- if not all(isinstance(t, type) for t in target):
672
- raise TypeError("If target is a sequence, all its elements must be types.")
673
- return convert_sequence_to_pydantic_model(
674
- cast(Sequence[Type], target), name, description, field_name, default
675
- )
676
-
677
- # Handle dictionaries
678
- if isinstance(target, dict):
679
- return convert_dict_to_pydantic_model(target, init, name, description)
680
-
681
- else:
682
- logger.error(
683
- f"Unsupported target type for Pydantic model creation: {type(target)} | how did you get here?"
684
- )
685
- raise TypeError(
686
- f"Cannot create Pydantic model from target of type {type(target)}"
687
- )
688
-
689
-
690
- # -----------------------------------------------------------------------------
691
- # Specialized Model Creation Utils
692
- # -----------------------------------------------------------------------------
693
-
694
-
695
- def create_selection_pydantic_model(
696
- fields: List[str],
697
- name: str = "Selection",
698
- description: Optional[str] = None,
699
- ) -> Type[BaseModel]:
700
- """
701
- Creates a Pydantic model for making a selection from a list of string options.
702
- The model will have a single field named `selection` of type `Literal[*fields]`.
703
-
704
- Args:
705
- fields: A list of strings representing the allowed choices. Must not be empty.
706
- name: The name for the created Pydantic model.
707
- description: Optional description for the model (becomes its docstring).
708
-
709
- Returns:
710
- A new Pydantic BaseModel class with a 'selection' field.
711
- Raises:
712
- ValueError: If `fields` is empty.
713
- """
714
- if not fields:
715
- raise ValueError(
716
- "`fields` list cannot be empty for `create_selection_pydantic_model`."
717
- )
718
-
719
- literal_args_str = ", ".join(repr(str(f)) for f in fields)
720
- selection_type = eval(f"Literal[{literal_args_str}]")
721
-
722
- model_fields_definitions = {
723
- "selection": (
724
- selection_type,
725
- Field(..., description="The selected value from the available options."),
726
- )
727
- }
728
- model_docstring = (
729
- description or f"A model for selecting one option from: {', '.join(fields)}."
730
- )
731
- return create_model(
732
- name, __base__=BaseModel, __doc__=model_docstring, **model_fields_definitions
733
- )
734
-
735
-
736
- def create_confirmation_pydantic_model(
737
- name: str = "Confirmation",
738
- description: Optional[str] = None,
739
- field_name: str = "confirmed",
740
- ) -> Type[BaseModel]:
741
- """
742
- Creates a Pydantic model for a boolean confirmation.
743
- The model will have a single boolean field.
744
-
745
- Args:
746
- name: The name for the created Pydantic model.
747
- description: Optional description for the model.
748
- field_name: Name of the boolean field in the model.
749
-
750
- Returns:
751
- A new Pydantic BaseModel class.
752
- """
753
- model_fields_definitions = {
754
- field_name: (bool, Field(..., description="The boolean confirmation value."))
755
- }
756
- model_docstring = description or "A model for boolean confirmation."
757
- return create_model(
758
- name, __base__=BaseModel, __doc__=model_docstring, **model_fields_definitions
759
- )