hammad-python 0.0.30__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.
- ham/__init__.py +10 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/METADATA +6 -32
- hammad_python-0.0.31.dist-info/RECORD +6 -0
- hammad/__init__.py +0 -84
- hammad/_internal.py +0 -256
- hammad/_main.py +0 -226
- hammad/cache/__init__.py +0 -40
- 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 -573
- hammad/cli/plugins.py +0 -867
- 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 -634
- hammad/data/__init__.py +0 -90
- hammad/data/collections/__init__.py +0 -49
- hammad/data/collections/collection.py +0 -326
- hammad/data/collections/indexes/__init__.py +0 -37
- hammad/data/collections/indexes/qdrant/__init__.py +0 -1
- hammad/data/collections/indexes/qdrant/index.py +0 -723
- hammad/data/collections/indexes/qdrant/settings.py +0 -94
- hammad/data/collections/indexes/qdrant/utils.py +0 -210
- hammad/data/collections/indexes/tantivy/__init__.py +0 -1
- hammad/data/collections/indexes/tantivy/index.py +0 -426
- hammad/data/collections/indexes/tantivy/settings.py +0 -40
- hammad/data/collections/indexes/tantivy/utils.py +0 -176
- hammad/data/configurations/__init__.py +0 -35
- hammad/data/configurations/configuration.py +0 -564
- hammad/data/models/__init__.py +0 -50
- hammad/data/models/extensions/__init__.py +0 -4
- hammad/data/models/extensions/pydantic/__init__.py +0 -42
- hammad/data/models/extensions/pydantic/converters.py +0 -759
- hammad/data/models/fields.py +0 -546
- hammad/data/models/model.py +0 -1078
- hammad/data/models/utils.py +0 -280
- hammad/data/sql/__init__.py +0 -24
- hammad/data/sql/database.py +0 -576
- hammad/data/sql/types.py +0 -127
- hammad/data/types/__init__.py +0 -75
- hammad/data/types/file.py +0 -431
- hammad/data/types/multimodal/__init__.py +0 -36
- hammad/data/types/multimodal/audio.py +0 -200
- hammad/data/types/multimodal/image.py +0 -182
- hammad/data/types/text.py +0 -1308
- hammad/formatting/__init__.py +0 -33
- hammad/formatting/json/__init__.py +0 -27
- hammad/formatting/json/converters.py +0 -158
- hammad/formatting/text/__init__.py +0 -63
- hammad/formatting/text/converters.py +0 -723
- hammad/formatting/text/markdown.py +0 -131
- hammad/formatting/yaml/__init__.py +0 -26
- hammad/formatting/yaml/converters.py +0 -5
- hammad/genai/__init__.py +0 -217
- hammad/genai/a2a/__init__.py +0 -32
- hammad/genai/a2a/workers.py +0 -552
- hammad/genai/agents/__init__.py +0 -59
- hammad/genai/agents/agent.py +0 -1973
- hammad/genai/agents/run.py +0 -1024
- hammad/genai/agents/types/__init__.py +0 -42
- hammad/genai/agents/types/agent_context.py +0 -13
- hammad/genai/agents/types/agent_event.py +0 -128
- hammad/genai/agents/types/agent_hooks.py +0 -220
- hammad/genai/agents/types/agent_messages.py +0 -31
- hammad/genai/agents/types/agent_response.py +0 -125
- hammad/genai/agents/types/agent_stream.py +0 -327
- hammad/genai/graphs/__init__.py +0 -125
- hammad/genai/graphs/_utils.py +0 -190
- hammad/genai/graphs/base.py +0 -1828
- hammad/genai/graphs/plugins.py +0 -316
- hammad/genai/graphs/types.py +0 -638
- hammad/genai/models/__init__.py +0 -1
- hammad/genai/models/embeddings/__init__.py +0 -43
- hammad/genai/models/embeddings/model.py +0 -226
- hammad/genai/models/embeddings/run.py +0 -163
- hammad/genai/models/embeddings/types/__init__.py +0 -37
- hammad/genai/models/embeddings/types/embedding_model_name.py +0 -75
- hammad/genai/models/embeddings/types/embedding_model_response.py +0 -76
- hammad/genai/models/embeddings/types/embedding_model_run_params.py +0 -66
- hammad/genai/models/embeddings/types/embedding_model_settings.py +0 -47
- hammad/genai/models/language/__init__.py +0 -57
- hammad/genai/models/language/model.py +0 -1098
- hammad/genai/models/language/run.py +0 -878
- hammad/genai/models/language/types/__init__.py +0 -40
- hammad/genai/models/language/types/language_model_instructor_mode.py +0 -47
- hammad/genai/models/language/types/language_model_messages.py +0 -28
- hammad/genai/models/language/types/language_model_name.py +0 -239
- hammad/genai/models/language/types/language_model_request.py +0 -127
- hammad/genai/models/language/types/language_model_response.py +0 -217
- hammad/genai/models/language/types/language_model_response_chunk.py +0 -56
- hammad/genai/models/language/types/language_model_settings.py +0 -89
- hammad/genai/models/language/types/language_model_stream.py +0 -600
- hammad/genai/models/language/utils/__init__.py +0 -28
- hammad/genai/models/language/utils/requests.py +0 -421
- hammad/genai/models/language/utils/structured_outputs.py +0 -135
- hammad/genai/models/model_provider.py +0 -4
- hammad/genai/models/multimodal.py +0 -47
- hammad/genai/models/reranking.py +0 -26
- hammad/genai/types/__init__.py +0 -1
- hammad/genai/types/base.py +0 -215
- hammad/genai/types/history.py +0 -290
- hammad/genai/types/tools.py +0 -507
- hammad/logging/__init__.py +0 -35
- hammad/logging/decorators.py +0 -834
- hammad/logging/logger.py +0 -1018
- hammad/mcp/__init__.py +0 -53
- hammad/mcp/client/__init__.py +0 -35
- hammad/mcp/client/client.py +0 -624
- hammad/mcp/client/client_service.py +0 -400
- hammad/mcp/client/settings.py +0 -178
- hammad/mcp/servers/__init__.py +0 -26
- hammad/mcp/servers/launcher.py +0 -1161
- hammad/runtime/__init__.py +0 -32
- hammad/runtime/decorators.py +0 -142
- hammad/runtime/run.py +0 -299
- hammad/service/__init__.py +0 -49
- hammad/service/create.py +0 -527
- hammad/service/decorators.py +0 -283
- hammad/types.py +0 -288
- hammad/typing/__init__.py +0 -435
- 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 -275
- hammad/web/openapi/__init__.py +0 -1
- hammad/web/openapi/client.py +0 -740
- hammad/web/search/__init__.py +0 -1
- hammad/web/search/client.py +0 -1023
- hammad/web/utils.py +0 -472
- hammad_python-0.0.30.dist-info/RECORD +0 -135
- {hammad → ham}/py.typed +0 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/WHEEL +0 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/licenses/LICENSE +0 -0
hammad/data/models/fields.py
DELETED
@@ -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
|
-
)
|