dhi 1.1.1__cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.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.
- dhi/__init__.py +173 -0
- dhi/_dhi_native.cpython-313-aarch64-linux-gnu.so +0 -0
- dhi/_native.c +379 -0
- dhi/batch.py +236 -0
- dhi/constraints.py +358 -0
- dhi/datetime_types.py +108 -0
- dhi/fields.py +187 -0
- dhi/functional_validators.py +108 -0
- dhi/libsatya.so +0 -0
- dhi/model.py +658 -0
- dhi/networks.py +290 -0
- dhi/secret.py +105 -0
- dhi/special_types.py +359 -0
- dhi/types.py +345 -0
- dhi/validator.py +212 -0
- dhi-1.1.1.dist-info/METADATA +115 -0
- dhi-1.1.1.dist-info/RECORD +21 -0
- dhi-1.1.1.dist-info/WHEEL +6 -0
- dhi-1.1.1.dist-info/licenses/LICENSE +21 -0
- dhi-1.1.1.dist-info/top_level.txt +1 -0
- dhi.libs/libsatya-a22d98f4.so +0 -0
dhi/fields.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Field definition for dhi - Pydantic v2 compatible.
|
|
3
|
+
|
|
4
|
+
Provides the Field() function for defining field-level constraints
|
|
5
|
+
and metadata, matching Pydantic's API.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
from typing import Annotated
|
|
9
|
+
from dhi import BaseModel, Field
|
|
10
|
+
|
|
11
|
+
class User(BaseModel):
|
|
12
|
+
name: Annotated[str, Field(min_length=1, max_length=100)]
|
|
13
|
+
age: Annotated[int, Field(gt=0, le=120)]
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import Any, Optional, Union, List
|
|
17
|
+
|
|
18
|
+
_MISSING = object() # Sentinel for unset defaults
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FieldInfo:
|
|
22
|
+
"""Stores field constraints and metadata.
|
|
23
|
+
|
|
24
|
+
This is the object returned by Field() and can be used in Annotated types.
|
|
25
|
+
"""
|
|
26
|
+
__slots__ = (
|
|
27
|
+
'default', 'default_factory', 'alias', 'title', 'description',
|
|
28
|
+
'examples', 'gt', 'ge', 'lt', 'le', 'multiple_of', 'strict',
|
|
29
|
+
'min_length', 'max_length', 'pattern', 'strip_whitespace',
|
|
30
|
+
'to_lower', 'to_upper', 'allow_inf_nan', 'max_digits',
|
|
31
|
+
'decimal_places', 'unique_items',
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
default: Any = _MISSING,
|
|
37
|
+
*,
|
|
38
|
+
default_factory: Any = None,
|
|
39
|
+
alias: Optional[str] = None,
|
|
40
|
+
title: Optional[str] = None,
|
|
41
|
+
description: Optional[str] = None,
|
|
42
|
+
examples: Optional[List[Any]] = None,
|
|
43
|
+
gt: Optional[Union[int, float]] = None,
|
|
44
|
+
ge: Optional[Union[int, float]] = None,
|
|
45
|
+
lt: Optional[Union[int, float]] = None,
|
|
46
|
+
le: Optional[Union[int, float]] = None,
|
|
47
|
+
multiple_of: Optional[Union[int, float]] = None,
|
|
48
|
+
strict: Optional[bool] = None,
|
|
49
|
+
min_length: Optional[int] = None,
|
|
50
|
+
max_length: Optional[int] = None,
|
|
51
|
+
pattern: Optional[str] = None,
|
|
52
|
+
strip_whitespace: Optional[bool] = None,
|
|
53
|
+
to_lower: Optional[bool] = None,
|
|
54
|
+
to_upper: Optional[bool] = None,
|
|
55
|
+
allow_inf_nan: Optional[bool] = None,
|
|
56
|
+
max_digits: Optional[int] = None,
|
|
57
|
+
decimal_places: Optional[int] = None,
|
|
58
|
+
unique_items: Optional[bool] = None,
|
|
59
|
+
):
|
|
60
|
+
self.default = default
|
|
61
|
+
self.default_factory = default_factory
|
|
62
|
+
self.alias = alias
|
|
63
|
+
self.title = title
|
|
64
|
+
self.description = description
|
|
65
|
+
self.examples = examples
|
|
66
|
+
self.gt = gt
|
|
67
|
+
self.ge = ge
|
|
68
|
+
self.lt = lt
|
|
69
|
+
self.le = le
|
|
70
|
+
self.multiple_of = multiple_of
|
|
71
|
+
self.strict = strict
|
|
72
|
+
self.min_length = min_length
|
|
73
|
+
self.max_length = max_length
|
|
74
|
+
self.pattern = pattern
|
|
75
|
+
self.strip_whitespace = strip_whitespace
|
|
76
|
+
self.to_lower = to_lower
|
|
77
|
+
self.to_upper = to_upper
|
|
78
|
+
self.allow_inf_nan = allow_inf_nan
|
|
79
|
+
self.max_digits = max_digits
|
|
80
|
+
self.decimal_places = decimal_places
|
|
81
|
+
self.unique_items = unique_items
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def is_required(self) -> bool:
|
|
85
|
+
return self.default is _MISSING and self.default_factory is None
|
|
86
|
+
|
|
87
|
+
def get_default(self) -> Any:
|
|
88
|
+
if self.default_factory is not None:
|
|
89
|
+
return self.default_factory()
|
|
90
|
+
if self.default is _MISSING:
|
|
91
|
+
raise ValueError("Field is required")
|
|
92
|
+
return self.default
|
|
93
|
+
|
|
94
|
+
def __repr__(self) -> str:
|
|
95
|
+
parts = []
|
|
96
|
+
if self.default is not _MISSING:
|
|
97
|
+
parts.append(f"default={self.default!r}")
|
|
98
|
+
if self.gt is not None:
|
|
99
|
+
parts.append(f"gt={self.gt}")
|
|
100
|
+
if self.ge is not None:
|
|
101
|
+
parts.append(f"ge={self.ge}")
|
|
102
|
+
if self.lt is not None:
|
|
103
|
+
parts.append(f"lt={self.lt}")
|
|
104
|
+
if self.le is not None:
|
|
105
|
+
parts.append(f"le={self.le}")
|
|
106
|
+
if self.multiple_of is not None:
|
|
107
|
+
parts.append(f"multiple_of={self.multiple_of}")
|
|
108
|
+
if self.min_length is not None:
|
|
109
|
+
parts.append(f"min_length={self.min_length}")
|
|
110
|
+
if self.max_length is not None:
|
|
111
|
+
parts.append(f"max_length={self.max_length}")
|
|
112
|
+
if self.pattern is not None:
|
|
113
|
+
parts.append(f"pattern={self.pattern!r}")
|
|
114
|
+
if self.strict:
|
|
115
|
+
parts.append("strict=True")
|
|
116
|
+
return f"FieldInfo({', '.join(parts)})"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def Field(
|
|
120
|
+
default: Any = _MISSING,
|
|
121
|
+
*,
|
|
122
|
+
default_factory: Any = None,
|
|
123
|
+
alias: Optional[str] = None,
|
|
124
|
+
title: Optional[str] = None,
|
|
125
|
+
description: Optional[str] = None,
|
|
126
|
+
examples: Optional[List[Any]] = None,
|
|
127
|
+
gt: Optional[Union[int, float]] = None,
|
|
128
|
+
ge: Optional[Union[int, float]] = None,
|
|
129
|
+
lt: Optional[Union[int, float]] = None,
|
|
130
|
+
le: Optional[Union[int, float]] = None,
|
|
131
|
+
multiple_of: Optional[Union[int, float]] = None,
|
|
132
|
+
strict: Optional[bool] = None,
|
|
133
|
+
min_length: Optional[int] = None,
|
|
134
|
+
max_length: Optional[int] = None,
|
|
135
|
+
pattern: Optional[str] = None,
|
|
136
|
+
strip_whitespace: Optional[bool] = None,
|
|
137
|
+
to_lower: Optional[bool] = None,
|
|
138
|
+
to_upper: Optional[bool] = None,
|
|
139
|
+
allow_inf_nan: Optional[bool] = None,
|
|
140
|
+
max_digits: Optional[int] = None,
|
|
141
|
+
decimal_places: Optional[int] = None,
|
|
142
|
+
unique_items: Optional[bool] = None,
|
|
143
|
+
) -> FieldInfo:
|
|
144
|
+
"""Create a FieldInfo with constraints and metadata.
|
|
145
|
+
|
|
146
|
+
Matches Pydantic v2's Field() function signature.
|
|
147
|
+
|
|
148
|
+
Example:
|
|
149
|
+
from typing import Annotated
|
|
150
|
+
from dhi import Field
|
|
151
|
+
|
|
152
|
+
# Numeric constraints
|
|
153
|
+
age: Annotated[int, Field(gt=0, le=120)]
|
|
154
|
+
|
|
155
|
+
# String constraints
|
|
156
|
+
name: Annotated[str, Field(min_length=1, max_length=50)]
|
|
157
|
+
|
|
158
|
+
# With default
|
|
159
|
+
score: Annotated[float, Field(default=0.0, ge=0, le=100)]
|
|
160
|
+
"""
|
|
161
|
+
return FieldInfo(
|
|
162
|
+
default=default,
|
|
163
|
+
default_factory=default_factory,
|
|
164
|
+
alias=alias,
|
|
165
|
+
title=title,
|
|
166
|
+
description=description,
|
|
167
|
+
examples=examples,
|
|
168
|
+
gt=gt,
|
|
169
|
+
ge=ge,
|
|
170
|
+
lt=lt,
|
|
171
|
+
le=le,
|
|
172
|
+
multiple_of=multiple_of,
|
|
173
|
+
strict=strict,
|
|
174
|
+
min_length=min_length,
|
|
175
|
+
max_length=max_length,
|
|
176
|
+
pattern=pattern,
|
|
177
|
+
strip_whitespace=strip_whitespace,
|
|
178
|
+
to_lower=to_lower,
|
|
179
|
+
to_upper=to_upper,
|
|
180
|
+
allow_inf_nan=allow_inf_nan,
|
|
181
|
+
max_digits=max_digits,
|
|
182
|
+
decimal_places=decimal_places,
|
|
183
|
+
unique_items=unique_items,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
__all__ = ["Field", "FieldInfo"]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Functional validators for dhi - Pydantic v2 compatible.
|
|
3
|
+
|
|
4
|
+
Provides decorator-based validators that can be applied to BaseModel fields
|
|
5
|
+
and models, matching Pydantic's @field_validator and @model_validator.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
from dhi import BaseModel, field_validator, model_validator
|
|
9
|
+
|
|
10
|
+
class User(BaseModel):
|
|
11
|
+
name: str
|
|
12
|
+
password: str
|
|
13
|
+
confirm_password: str
|
|
14
|
+
|
|
15
|
+
@field_validator('name')
|
|
16
|
+
@classmethod
|
|
17
|
+
def name_must_be_alpha(cls, v):
|
|
18
|
+
if not v.isalpha():
|
|
19
|
+
raise ValueError('Name must be alphabetic')
|
|
20
|
+
return v
|
|
21
|
+
|
|
22
|
+
@model_validator(mode='after')
|
|
23
|
+
def passwords_match(self):
|
|
24
|
+
if self.password != self.confirm_password:
|
|
25
|
+
raise ValueError('Passwords do not match')
|
|
26
|
+
return self
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from typing import Any, Callable, Optional, Sequence, Union
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def field_validator(
|
|
33
|
+
*fields: str,
|
|
34
|
+
mode: str = 'after',
|
|
35
|
+
) -> Callable:
|
|
36
|
+
"""Decorator for field-level custom validation.
|
|
37
|
+
|
|
38
|
+
Matches Pydantic v2's @field_validator decorator.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
*fields: Field names this validator applies to.
|
|
42
|
+
mode: 'before' for pre-validation, 'after' for post-validation.
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
class Model(BaseModel):
|
|
46
|
+
name: str
|
|
47
|
+
|
|
48
|
+
@field_validator('name')
|
|
49
|
+
@classmethod
|
|
50
|
+
def validate_name(cls, v):
|
|
51
|
+
if len(v) < 2:
|
|
52
|
+
raise ValueError('Name too short')
|
|
53
|
+
return v.title()
|
|
54
|
+
"""
|
|
55
|
+
def decorator(func: Callable) -> Callable:
|
|
56
|
+
func.__validator_fields__ = fields
|
|
57
|
+
func.__validator_mode__ = mode
|
|
58
|
+
return func
|
|
59
|
+
return decorator
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def model_validator(
|
|
63
|
+
*,
|
|
64
|
+
mode: str = 'after',
|
|
65
|
+
) -> Callable:
|
|
66
|
+
"""Decorator for model-level custom validation.
|
|
67
|
+
|
|
68
|
+
Matches Pydantic v2's @model_validator decorator.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
mode: 'before' runs before field validation (receives raw data dict),
|
|
72
|
+
'after' runs after field validation (receives model instance).
|
|
73
|
+
|
|
74
|
+
Example:
|
|
75
|
+
class Model(BaseModel):
|
|
76
|
+
start: int
|
|
77
|
+
end: int
|
|
78
|
+
|
|
79
|
+
@model_validator(mode='after')
|
|
80
|
+
def check_order(self):
|
|
81
|
+
if self.start >= self.end:
|
|
82
|
+
raise ValueError('start must be less than end')
|
|
83
|
+
return self
|
|
84
|
+
"""
|
|
85
|
+
def decorator(func: Callable) -> Callable:
|
|
86
|
+
func.__model_validator__ = True
|
|
87
|
+
func.__validator_mode__ = mode
|
|
88
|
+
return func
|
|
89
|
+
return decorator
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def validator(
|
|
93
|
+
*fields: str,
|
|
94
|
+
pre: bool = False,
|
|
95
|
+
always: bool = False,
|
|
96
|
+
) -> Callable:
|
|
97
|
+
"""Legacy Pydantic v1 style validator (for backward compatibility).
|
|
98
|
+
|
|
99
|
+
Prefer @field_validator for new code.
|
|
100
|
+
"""
|
|
101
|
+
def decorator(func: Callable) -> Callable:
|
|
102
|
+
func.__validator_fields__ = fields
|
|
103
|
+
func.__validator_mode__ = 'before' if pre else 'after'
|
|
104
|
+
return func
|
|
105
|
+
return decorator
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
__all__ = ["field_validator", "model_validator", "validator"]
|
dhi/libsatya.so
ADDED
|
Binary file
|