hammad-python 0.0.14__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.
Files changed (101) hide show
  1. hammad_python-0.0.15.dist-info/METADATA +184 -0
  2. hammad_python-0.0.15.dist-info/RECORD +4 -0
  3. hammad/__init__.py +0 -1
  4. hammad/ai/__init__.py +0 -1
  5. hammad/ai/_utils.py +0 -142
  6. hammad/ai/completions/__init__.py +0 -45
  7. hammad/ai/completions/client.py +0 -684
  8. hammad/ai/completions/create.py +0 -710
  9. hammad/ai/completions/settings.py +0 -100
  10. hammad/ai/completions/types.py +0 -792
  11. hammad/ai/completions/utils.py +0 -486
  12. hammad/ai/embeddings/__init__.py +0 -35
  13. hammad/ai/embeddings/client/__init__.py +0 -1
  14. hammad/ai/embeddings/client/base_embeddings_client.py +0 -26
  15. hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +0 -200
  16. hammad/ai/embeddings/client/litellm_embeddings_client.py +0 -288
  17. hammad/ai/embeddings/create.py +0 -159
  18. hammad/ai/embeddings/types.py +0 -69
  19. hammad/cache/__init__.py +0 -40
  20. hammad/cache/base_cache.py +0 -181
  21. hammad/cache/cache.py +0 -169
  22. hammad/cache/decorators.py +0 -261
  23. hammad/cache/file_cache.py +0 -80
  24. hammad/cache/ttl_cache.py +0 -74
  25. hammad/cli/__init__.py +0 -33
  26. hammad/cli/animations.py +0 -573
  27. hammad/cli/plugins.py +0 -781
  28. hammad/cli/styles/__init__.py +0 -55
  29. hammad/cli/styles/settings.py +0 -139
  30. hammad/cli/styles/types.py +0 -358
  31. hammad/cli/styles/utils.py +0 -480
  32. hammad/data/__init__.py +0 -56
  33. hammad/data/collections/__init__.py +0 -34
  34. hammad/data/collections/base_collection.py +0 -58
  35. hammad/data/collections/collection.py +0 -452
  36. hammad/data/collections/searchable_collection.py +0 -556
  37. hammad/data/collections/vector_collection.py +0 -596
  38. hammad/data/configurations/__init__.py +0 -35
  39. hammad/data/configurations/configuration.py +0 -564
  40. hammad/data/databases/__init__.py +0 -21
  41. hammad/data/databases/database.py +0 -902
  42. hammad/data/models/__init__.py +0 -44
  43. hammad/data/models/base/__init__.py +0 -35
  44. hammad/data/models/base/fields.py +0 -546
  45. hammad/data/models/base/model.py +0 -1078
  46. hammad/data/models/base/utils.py +0 -280
  47. hammad/data/models/pydantic/__init__.py +0 -55
  48. hammad/data/models/pydantic/converters.py +0 -632
  49. hammad/data/models/pydantic/models/__init__.py +0 -28
  50. hammad/data/models/pydantic/models/arbitrary_model.py +0 -46
  51. hammad/data/models/pydantic/models/cacheable_model.py +0 -79
  52. hammad/data/models/pydantic/models/fast_model.py +0 -318
  53. hammad/data/models/pydantic/models/function_model.py +0 -176
  54. hammad/data/models/pydantic/models/subscriptable_model.py +0 -63
  55. hammad/data/types/__init__.py +0 -41
  56. hammad/data/types/file.py +0 -358
  57. hammad/data/types/multimodal/__init__.py +0 -24
  58. hammad/data/types/multimodal/audio.py +0 -96
  59. hammad/data/types/multimodal/image.py +0 -80
  60. hammad/data/types/text.py +0 -1066
  61. hammad/formatting/__init__.py +0 -38
  62. hammad/formatting/json/__init__.py +0 -21
  63. hammad/formatting/json/converters.py +0 -152
  64. hammad/formatting/text/__init__.py +0 -63
  65. hammad/formatting/text/converters.py +0 -723
  66. hammad/formatting/text/markdown.py +0 -131
  67. hammad/formatting/yaml/__init__.py +0 -26
  68. hammad/formatting/yaml/converters.py +0 -5
  69. hammad/logging/__init__.py +0 -35
  70. hammad/logging/decorators.py +0 -834
  71. hammad/logging/logger.py +0 -954
  72. hammad/mcp/__init__.py +0 -50
  73. hammad/mcp/client/__init__.py +0 -1
  74. hammad/mcp/client/client.py +0 -523
  75. hammad/mcp/client/client_service.py +0 -393
  76. hammad/mcp/client/settings.py +0 -178
  77. hammad/mcp/servers/__init__.py +0 -1
  78. hammad/mcp/servers/launcher.py +0 -1161
  79. hammad/performance/__init__.py +0 -36
  80. hammad/performance/imports.py +0 -231
  81. hammad/performance/runtime/__init__.py +0 -32
  82. hammad/performance/runtime/decorators.py +0 -142
  83. hammad/performance/runtime/run.py +0 -299
  84. hammad/py.typed +0 -0
  85. hammad/service/__init__.py +0 -49
  86. hammad/service/create.py +0 -532
  87. hammad/service/decorators.py +0 -285
  88. hammad/typing/__init__.py +0 -407
  89. hammad/web/__init__.py +0 -43
  90. hammad/web/http/__init__.py +0 -1
  91. hammad/web/http/client.py +0 -944
  92. hammad/web/models.py +0 -245
  93. hammad/web/openapi/__init__.py +0 -1
  94. hammad/web/openapi/client.py +0 -740
  95. hammad/web/search/__init__.py +0 -1
  96. hammad/web/search/client.py +0 -988
  97. hammad/web/utils.py +0 -472
  98. hammad_python-0.0.14.dist-info/METADATA +0 -70
  99. hammad_python-0.0.14.dist-info/RECORD +0 -99
  100. {hammad_python-0.0.14.dist-info → hammad_python-0.0.15.dist-info}/WHEEL +0 -0
  101. {hammad_python-0.0.14.dist-info → hammad_python-0.0.15.dist-info}/licenses/LICENSE +0 -0
@@ -1,44 +0,0 @@
1
- """hammad.data.models
2
-
3
- Contains **BOTH** resources contains predefined models or base class like
4
- models, as well as modules & utilities specifically for various interfaces
5
- of models such as `pydantic`."""
6
-
7
- from typing import TYPE_CHECKING
8
- from ...performance.imports import create_getattr_importer
9
-
10
- if TYPE_CHECKING:
11
- from .base import (
12
- Model,
13
- field,
14
- validator,
15
- is_field,
16
- is_model,
17
- model_settings
18
- )
19
- from .pydantic import (
20
- convert_to_pydantic_model,
21
- convert_to_pydantic_field
22
- )
23
-
24
-
25
- __all__ = (
26
- # hammad.models.base
27
- "Model",
28
- "field",
29
- "validator",
30
- "is_field",
31
- "is_model",
32
- "model_settings",
33
-
34
- # hammad.models.pydantic
35
- "convert_to_pydantic_model",
36
- "convert_to_pydantic_field",
37
- )
38
-
39
-
40
- __getattr__ = create_getattr_importer(__all__)
41
-
42
-
43
- def __dir__() -> list[str]:
44
- return list(__all__)
@@ -1,35 +0,0 @@
1
- """hammad.models.base
2
-
3
- Contains the `Model` and `field` system along with an assortment
4
- of various utilities for interacting and managing these objects.
5
- """
6
-
7
- from typing import TYPE_CHECKING
8
- from ....performance.imports import create_getattr_importer
9
-
10
- if TYPE_CHECKING:
11
- from .model import Model, model_settings
12
- from .fields import field, Field, FieldInfo
13
- from .utils import create_model, validator, is_field, is_model, get_field_info
14
-
15
- __all__ = (
16
- # hammad.models.model
17
- "Model",
18
- "model_settings",
19
- # hammad.models.fields
20
- "field",
21
- "Field",
22
- "FieldInfo",
23
- # hammad.models.utils
24
- "create_model",
25
- "validator",
26
- "is_field",
27
- "is_model",
28
- "get_field_info",
29
- )
30
-
31
- __getattr__ = create_getattr_importer(__all__)
32
-
33
-
34
- def __dir__() -> list[str]:
35
- return list(__all__)
@@ -1,546 +0,0 @@
1
- """hammad.base.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
- )