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,546 +0,0 @@
1
- """hammad.data.models.fields"""
2
-
3
- import re
4
- from dataclasses import dataclass
5
- from functools import lru_cache
6
- from typing import Any, Callable, Dict, List, Literal, Optional, Pattern, Set, Union
7
-
8
- import msgspec
9
- from msgspec import field as msgspec_field
10
-
11
- __all__ = (
12
- "FieldInfo",
13
- "field",
14
- "Field",
15
- "str_field",
16
- "int_field",
17
- "float_field",
18
- "list_field",
19
- )
20
-
21
-
22
- @dataclass(frozen=True, slots=True)
23
- class FieldInfo:
24
- """Immutable field information container optimized for performance.
25
-
26
- Uses frozen dataclass with slots for memory efficiency and faster attribute access.
27
- """
28
-
29
- # Core field configuration
30
- default: Any = msgspec.UNSET
31
- default_factory: Optional[Callable[[], Any]] = None
32
-
33
- # Naming and aliases
34
- alias: Optional[str] = None
35
- validation_alias: Optional[str] = None
36
- serialization_alias: Optional[str] = None
37
-
38
- # Documentation
39
- title: Optional[str] = None
40
- description: Optional[str] = None
41
- examples: Optional[List[Any]] = None
42
-
43
- # Serialization control
44
- exclude: bool = False
45
- include: bool = True
46
- repr: bool = True
47
-
48
- # Validation configuration
49
- strict: bool = False
50
- validate_default: bool = False
51
- frozen: bool = False
52
- allow_mutation: bool = True
53
-
54
- # Numeric constraints
55
- gt: Optional[Union[int, float]] = None
56
- ge: Optional[Union[int, float]] = None
57
- lt: Optional[Union[int, float]] = None
58
- le: Optional[Union[int, float]] = None
59
- multiple_of: Optional[Union[int, float]] = None
60
- allow_inf_nan: bool = True
61
-
62
- # String constraints
63
- pattern: Optional[Union[str, Pattern[str]]] = None
64
- strip_whitespace: bool = False
65
- to_lower: bool = False
66
- to_upper: bool = False
67
-
68
- # Collection constraints
69
- min_length: Optional[int] = None
70
- max_length: Optional[int] = None
71
- unique_items: bool = False
72
-
73
- # Advanced configuration
74
- discriminator: Optional[str] = None
75
- json_schema_extra: Optional[Dict[str, Any]] = None
76
- kw_only: bool = False
77
- init: bool = True
78
- init_var: bool = False
79
-
80
- # Union handling
81
- union_mode: Literal["smart", "left_to_right"] = "smart"
82
-
83
- # Custom validators (stored as tuples for immutability)
84
- validators: tuple[Callable[[Any], Any], ...] = ()
85
- pre_validators: tuple[Callable[[Any], Any], ...] = ()
86
- post_validators: tuple[Callable[[Any], Any], ...] = ()
87
-
88
- def __post_init__(self):
89
- """Validate field configuration after initialization."""
90
- # Validate numeric constraints
91
- if self.gt is not None and self.ge is not None:
92
- raise ValueError("Cannot specify both 'gt' and 'ge'")
93
- if self.lt is not None and self.le is not None:
94
- raise ValueError("Cannot specify both 'lt' and 'le'")
95
-
96
- # Validate string pattern
97
- if self.pattern is not None and isinstance(self.pattern, str):
98
- try:
99
- object.__setattr__(self, "pattern", re.compile(self.pattern))
100
- except re.error as e:
101
- raise ValueError(f"Invalid regex pattern: {e}")
102
-
103
- # Ensure validators are tuples
104
- for attr in ("validators", "pre_validators", "post_validators"):
105
- val = getattr(self, attr)
106
- if not isinstance(val, tuple):
107
- object.__setattr__(self, attr, tuple(val) if val else ())
108
-
109
- @lru_cache(maxsize=None)
110
- def get_effective_alias(
111
- self, mode: Literal["validation", "serialization", "general"] = "general"
112
- ) -> Optional[str]:
113
- """Get the effective alias for a given mode with caching."""
114
- if mode == "validation" and self.validation_alias:
115
- return self.validation_alias
116
- elif mode == "serialization" and self.serialization_alias:
117
- return self.serialization_alias
118
- return self.alias
119
-
120
- def apply_constraints(self, value: Any, field_name: str) -> Any:
121
- """Apply validation constraints to a value."""
122
- # Pre-validators
123
- for validator in self.pre_validators:
124
- value = validator(value)
125
-
126
- # Type-specific constraints
127
- if isinstance(value, (int, float)):
128
- value = self._validate_numeric(value, field_name)
129
- elif isinstance(value, str):
130
- value = self._validate_string(value, field_name)
131
- elif isinstance(value, (list, tuple, set, frozenset)):
132
- value = self._validate_collection(value, field_name)
133
-
134
- # General validators
135
- for validator in self.validators:
136
- value = validator(value)
137
-
138
- # Post-validators
139
- for validator in self.post_validators:
140
- value = validator(value)
141
-
142
- return value
143
-
144
- def _validate_numeric(
145
- self, value: Union[int, float], field_name: str
146
- ) -> Union[int, float]:
147
- """Apply numeric constraints."""
148
- if not self.allow_inf_nan and isinstance(value, float):
149
- if value != value: # NaN check
150
- raise ValueError(f"{field_name}: NaN values are not allowed")
151
- if value == float("inf") or value == float("-inf"):
152
- raise ValueError(f"{field_name}: Infinite values are not allowed")
153
-
154
- if self.gt is not None and value <= self.gt:
155
- raise ValueError(f"{field_name}: {value} is not greater than {self.gt}")
156
- if self.ge is not None and value < self.ge:
157
- raise ValueError(
158
- f"{field_name}: {value} is not greater than or equal to {self.ge}"
159
- )
160
- if self.lt is not None and value >= self.lt:
161
- raise ValueError(f"{field_name}: {value} is not less than {self.lt}")
162
- if self.le is not None and value > self.le:
163
- raise ValueError(
164
- f"{field_name}: {value} is not less than or equal to {self.le}"
165
- )
166
-
167
- if self.multiple_of is not None:
168
- if isinstance(value, float) or isinstance(self.multiple_of, float):
169
- # Use float comparison with small epsilon for floats
170
- remainder = value % self.multiple_of
171
- if abs(remainder) > 1e-9 and abs(remainder - self.multiple_of) > 1e-9:
172
- raise ValueError(
173
- f"{field_name}: {value} is not a multiple of {self.multiple_of}"
174
- )
175
- else:
176
- # Exact comparison for integers
177
- if value % self.multiple_of != 0:
178
- raise ValueError(
179
- f"{field_name}: {value} is not a multiple of {self.multiple_of}"
180
- )
181
-
182
- return value
183
-
184
- def _validate_string(self, value: str, field_name: str) -> str:
185
- """Apply string constraints and transformations."""
186
- # Transformations
187
- if self.strip_whitespace:
188
- value = value.strip()
189
- if self.to_lower:
190
- value = value.lower()
191
- if self.to_upper:
192
- value = value.upper()
193
-
194
- # Length validation
195
- if self.min_length is not None and len(value) < self.min_length:
196
- raise ValueError(
197
- f"{field_name}: String length {len(value)} is less than minimum {self.min_length}"
198
- )
199
- if self.max_length is not None and len(value) > self.max_length:
200
- raise ValueError(
201
- f"{field_name}: String length {len(value)} exceeds maximum {self.max_length}"
202
- )
203
-
204
- # Pattern validation
205
- if self.pattern is not None:
206
- pattern = (
207
- self.pattern
208
- if isinstance(self.pattern, Pattern)
209
- else re.compile(self.pattern)
210
- )
211
- if not pattern.match(value):
212
- raise ValueError(
213
- f"{field_name}: String does not match pattern {pattern.pattern}"
214
- )
215
-
216
- return value
217
-
218
- def _validate_collection(
219
- self, value: Union[List, Set, tuple, frozenset], field_name: str
220
- ) -> Any:
221
- """Apply collection constraints."""
222
- # Length validation
223
- if self.min_length is not None and len(value) < self.min_length:
224
- raise ValueError(
225
- f"{field_name}: Collection length {len(value)} is less than minimum {self.min_length}"
226
- )
227
- if self.max_length is not None and len(value) > self.max_length:
228
- raise ValueError(
229
- f"{field_name}: Collection length {len(value)} exceeds maximum {self.max_length}"
230
- )
231
-
232
- # Unique items validation for lists/tuples
233
- if self.unique_items and isinstance(value, (list, tuple)):
234
- seen = set()
235
- for item in value:
236
- # Handle unhashable types
237
- try:
238
- if item in seen:
239
- raise ValueError(
240
- f"{field_name}: Duplicate items are not allowed"
241
- )
242
- seen.add(item)
243
- except TypeError:
244
- # For unhashable types, fall back to linear search
245
- if value.count(item) > 1:
246
- raise ValueError(
247
- f"{field_name}: Duplicate items are not allowed"
248
- )
249
-
250
- return value
251
-
252
- def to_json_schema(self) -> Dict[str, Any]:
253
- """Generate JSON schema for this field."""
254
- schema = {}
255
-
256
- if self.title:
257
- schema["title"] = self.title
258
- if self.description:
259
- schema["description"] = self.description
260
- if self.examples:
261
- schema["examples"] = self.examples
262
-
263
- # Numeric constraints
264
- if self.gt is not None:
265
- schema["exclusiveMinimum"] = self.gt
266
- if self.ge is not None:
267
- schema["minimum"] = self.ge
268
- if self.lt is not None:
269
- schema["exclusiveMaximum"] = self.lt
270
- if self.le is not None:
271
- schema["maximum"] = self.le
272
- if self.multiple_of is not None:
273
- schema["multipleOf"] = self.multiple_of
274
-
275
- # String constraints
276
- if self.pattern is not None:
277
- pattern = (
278
- self.pattern if isinstance(self.pattern, str) else self.pattern.pattern
279
- )
280
- schema["pattern"] = pattern
281
- if self.min_length is not None:
282
- schema["minLength"] = self.min_length
283
- if self.max_length is not None:
284
- schema["maxLength"] = self.max_length
285
-
286
- # Collection constraints
287
- if self.unique_items:
288
- schema["uniqueItems"] = True
289
-
290
- # Extra schema properties
291
- if self.json_schema_extra:
292
- schema.update(self.json_schema_extra)
293
-
294
- return schema
295
-
296
-
297
- class Field:
298
- """Field descriptor that combines msgspec.field with FieldInfo metadata.
299
-
300
- This class wraps msgspec's field functionality while preserving our
301
- extended metadata for validation and serialization.
302
- """
303
-
304
- def __init__(self, field_info: FieldInfo):
305
- self.field_info = field_info
306
- self._msgspec_field = None
307
-
308
- def __set_name__(self, owner, name):
309
- """Called when the descriptor is assigned to a class attribute."""
310
- self.name = name
311
-
312
- def to_msgspec(self) -> Any:
313
- """Convert to a msgspec field."""
314
- kwargs = {}
315
-
316
- # Handle default value
317
- if self.field_info.default is not msgspec.UNSET:
318
- kwargs["default"] = self.field_info.default
319
- elif self.field_info.default_factory is not None:
320
- kwargs["default_factory"] = self.field_info.default_factory
321
-
322
- # Handle field naming
323
- if self.field_info.alias:
324
- # Use Annotated with Meta for field renaming
325
- return msgspec_field(**kwargs)
326
-
327
- return msgspec_field(**kwargs)
328
-
329
- def __repr__(self):
330
- return f"Field({self.field_info})"
331
-
332
-
333
- def field(
334
- default: Any = msgspec.UNSET,
335
- *,
336
- default_factory: Optional[Callable[[], Any]] = None,
337
- alias: Optional[str] = None,
338
- validation_alias: Optional[str] = None,
339
- serialization_alias: Optional[str] = None,
340
- title: Optional[str] = None,
341
- description: Optional[str] = None,
342
- examples: Optional[List[Any]] = None,
343
- exclude: bool = False,
344
- include: bool = True,
345
- repr: bool = True,
346
- strict: bool = False,
347
- validate_default: bool = False,
348
- frozen: bool = False,
349
- allow_mutation: bool = True,
350
- gt: Optional[Union[int, float]] = None,
351
- ge: Optional[Union[int, float]] = None,
352
- lt: Optional[Union[int, float]] = None,
353
- le: Optional[Union[int, float]] = None,
354
- multiple_of: Optional[Union[int, float]] = None,
355
- allow_inf_nan: bool = True,
356
- pattern: Optional[Union[str, Pattern[str]]] = None,
357
- strip_whitespace: bool = False,
358
- to_lower: bool = False,
359
- to_upper: bool = False,
360
- min_length: Optional[int] = None,
361
- max_length: Optional[int] = None,
362
- unique_items: bool = False,
363
- discriminator: Optional[str] = None,
364
- json_schema_extra: Optional[Dict[str, Any]] = None,
365
- kw_only: bool = False,
366
- init: bool = True,
367
- init_var: bool = False,
368
- union_mode: Literal["smart", "left_to_right"] = "smart",
369
- validators: Optional[List[Callable[[Any], Any]]] = None,
370
- pre_validators: Optional[List[Callable[[Any], Any]]] = None,
371
- post_validators: Optional[List[Callable[[Any], Any]]] = None,
372
- ) -> Any:
373
- """Create a field descriptor for Model with Pydantic-like configuration.
374
-
375
- This function creates a field with validation, serialization, and schema
376
- generation capabilities while maintaining msgspec's performance benefits.
377
-
378
- Args:
379
- default: Default value for the field
380
- default_factory: Factory function to generate default values
381
- alias: Alternative name for the field in serialization/deserialization
382
- validation_alias: Specific alias for validation (input) only
383
- serialization_alias: Specific alias for serialization (output) only
384
- title: Human-readable title for documentation
385
- description: Human-readable description for documentation
386
- examples: List of example valid values
387
- exclude: Whether to exclude this field from serialization
388
- include: Whether to include this field in serialization
389
- repr: Whether to include in string representation
390
- strict: Whether to use strict type validation
391
- validate_default: Whether to validate the default value
392
- frozen: Whether the field is immutable after creation
393
- allow_mutation: Whether the field can be modified
394
- gt: Value must be greater than this
395
- ge: Value must be greater than or equal to this
396
- lt: Value must be less than this
397
- le: Value must be less than or equal to this
398
- multiple_of: Value must be a multiple of this
399
- allow_inf_nan: Whether to allow infinity and NaN for floats
400
- pattern: Regex pattern for string validation
401
- strip_whitespace: Whether to strip whitespace from strings
402
- to_lower: Whether to convert strings to lowercase
403
- to_upper: Whether to convert strings to uppercase
404
- min_length: Minimum length for strings/collections
405
- max_length: Maximum length for strings/collections
406
- unique_items: Whether collection items must be unique
407
- discriminator: Field name for discriminating unions
408
- json_schema_extra: Additional JSON schema properties
409
- kw_only: Whether the field is keyword-only in __init__
410
- init: Whether to include in __init__
411
- init_var: Whether the field is init-only
412
- union_mode: How to validate union types
413
- validators: List of validation functions
414
- pre_validators: List of pre-processing validators
415
- post_validators: List of post-processing validators
416
-
417
- Returns:
418
- Field descriptor or Annotated type with metadata for use with Model
419
- """
420
- # Store field info for potential future use (validation, schema generation, etc.)
421
- info = FieldInfo(
422
- default=default,
423
- default_factory=default_factory,
424
- alias=alias,
425
- validation_alias=validation_alias,
426
- serialization_alias=serialization_alias,
427
- title=title,
428
- description=description,
429
- examples=examples,
430
- exclude=exclude,
431
- include=include,
432
- repr=repr,
433
- strict=strict,
434
- validate_default=validate_default,
435
- frozen=frozen,
436
- allow_mutation=allow_mutation,
437
- gt=gt,
438
- ge=ge,
439
- lt=lt,
440
- le=le,
441
- multiple_of=multiple_of,
442
- allow_inf_nan=allow_inf_nan,
443
- pattern=pattern,
444
- strip_whitespace=strip_whitespace,
445
- to_lower=to_lower,
446
- to_upper=to_upper,
447
- min_length=min_length,
448
- max_length=max_length,
449
- unique_items=unique_items,
450
- discriminator=discriminator,
451
- json_schema_extra=json_schema_extra,
452
- kw_only=kw_only,
453
- init=init,
454
- init_var=init_var,
455
- union_mode=union_mode,
456
- validators=tuple(validators or []),
457
- pre_validators=tuple(pre_validators or []),
458
- post_validators=tuple(post_validators or []),
459
- )
460
-
461
- # Build the kwargs for the msgspec field
462
- kwargs = {}
463
- if default is not msgspec.UNSET:
464
- kwargs["default"] = default
465
- elif default_factory is not None:
466
- kwargs["default_factory"] = default_factory
467
-
468
- # Create the msgspec field with validation info embedded
469
- msgspec_field_instance = msgspec_field(**kwargs)
470
-
471
- # For now, just return the msgspec field - let msgspec handle everything
472
- return msgspec_field_instance
473
-
474
-
475
- def str_field(
476
- *,
477
- min_length: Optional[int] = None,
478
- max_length: Optional[int] = None,
479
- pattern: Optional[Union[str, Pattern[str]]] = None,
480
- strip_whitespace: bool = False,
481
- to_lower: bool = False,
482
- to_upper: bool = False,
483
- **kwargs,
484
- ) -> Any:
485
- """Create a string field with common string-specific options."""
486
- return field(
487
- min_length=min_length,
488
- max_length=max_length,
489
- pattern=pattern,
490
- strip_whitespace=strip_whitespace,
491
- to_lower=to_lower,
492
- to_upper=to_upper,
493
- **kwargs,
494
- )
495
-
496
-
497
- def int_field(
498
- *,
499
- gt: Optional[int] = None,
500
- ge: Optional[int] = None,
501
- lt: Optional[int] = None,
502
- le: Optional[int] = None,
503
- multiple_of: Optional[int] = None,
504
- **kwargs,
505
- ) -> Any:
506
- """Create an integer field with numeric constraints."""
507
- return field(gt=gt, ge=ge, lt=lt, le=le, multiple_of=multiple_of, **kwargs)
508
-
509
-
510
- def float_field(
511
- *,
512
- gt: Optional[float] = None,
513
- ge: Optional[float] = None,
514
- lt: Optional[float] = None,
515
- le: Optional[float] = None,
516
- multiple_of: Optional[float] = None,
517
- allow_inf_nan: bool = True,
518
- **kwargs,
519
- ) -> Any:
520
- """Create a float field with numeric constraints."""
521
- return field(
522
- gt=gt,
523
- ge=ge,
524
- lt=lt,
525
- le=le,
526
- multiple_of=multiple_of,
527
- allow_inf_nan=allow_inf_nan,
528
- **kwargs,
529
- )
530
-
531
-
532
- def list_field(
533
- *,
534
- min_length: Optional[int] = None,
535
- max_length: Optional[int] = None,
536
- unique_items: bool = False,
537
- **kwargs,
538
- ) -> Any:
539
- """Create a list field with collection constraints."""
540
- return field(
541
- default_factory=list,
542
- min_length=min_length,
543
- max_length=max_length,
544
- unique_items=unique_items,
545
- **kwargs,
546
- )