statica 1.0.0__tar.gz → 1.0.2__tar.gz
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.
- statica-1.0.2/PKG-INFO +226 -0
- statica-1.0.2/README.md +190 -0
- {statica-1.0.0 → statica-1.0.2}/pyproject.toml +5 -2
- statica-1.0.2/statica/__init__.py +10 -0
- {statica-1.0.0 → statica-1.0.2}/statica/core.py +8 -20
- statica-1.0.2/statica/exceptions.py +10 -0
- statica-1.0.2/statica.egg-info/PKG-INFO +226 -0
- {statica-1.0.0 → statica-1.0.2}/statica.egg-info/SOURCES.txt +1 -0
- statica-1.0.0/PKG-INFO +0 -38
- statica-1.0.0/README.md +0 -2
- statica-1.0.0/statica/__init__.py +0 -9
- statica-1.0.0/statica.egg-info/PKG-INFO +0 -38
- {statica-1.0.0 → statica-1.0.2}/LICENSE +0 -0
- {statica-1.0.0 → statica-1.0.2}/setup.cfg +0 -0
- {statica-1.0.0 → statica-1.0.2}/statica.egg-info/dependency_links.txt +0 -0
- {statica-1.0.0 → statica-1.0.2}/statica.egg-info/top_level.txt +0 -0
- {statica-1.0.0 → statica-1.0.2}/tests/test_statica.py +0 -0
statica-1.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: statica
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: A minimalistic data validation library
|
|
5
|
+
Author-email: Marcel Kröker <kroeker.marcel@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 mkrd
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Classifier: Programming Language :: Python :: 3
|
|
29
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
30
|
+
Classifier: Operating System :: OS Independent
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: Programming Language :: Python
|
|
33
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
34
|
+
Requires-Python: <3.14,>=3.11
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# Statica
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
Statica is a Python library for defining and validating structured data with type annotations and constraints. It provides an easy-to-use framework for creating type-safe models with comprehensive validation for both types and constraints.
|
|
44
|
+
|
|
45
|
+
## Why Statica?
|
|
46
|
+
|
|
47
|
+
Statica was created to address the need for a lightweight, flexible, and dependency-free alternative to libraries like pydantic.
|
|
48
|
+
While pydantic is a powerful tool for data validation and parsing, Statica offers some distinct advantages in specific situations:
|
|
49
|
+
|
|
50
|
+
1. **Lightweight**: Statica does not rely on any third-party dependencies, making it ideal for projects where minimizing external dependencies is a priority.
|
|
51
|
+
2. **Customizable Validation**: Statica allows fine-grained control over type and constraint validation through customizable field descriptors (`Field`) and error classes.
|
|
52
|
+
3. **Ease of Use**: With its simple, Pythonic design, Statica is intuitive for developers already familiar with Python's `dataclasses` and type hinting. It avoids much of the magic that pydantic employs.
|
|
53
|
+
4. **Performance**: For use cases where performance, especially memory usage, is critical, Statica avoids some of the overhead introduced by the advanced features of pydantic.
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
- **Type Validation**: Automatically validates types for attributes based on type hints.
|
|
58
|
+
- **Constraint Validation**: Define constraints like minimum/maximum length, value ranges, and more.
|
|
59
|
+
- **Customizable Error Handling**: Use custom exception classes for type and constraint errors.
|
|
60
|
+
- **Flexible Field Descriptors**: Add constraints, casting, and other behaviors to your fields.
|
|
61
|
+
- **Optional Fields**: Support for optional fields with default values.
|
|
62
|
+
- **Automatic Initialization**: Automatically generate constructors (`__init__`) for your models.
|
|
63
|
+
- **String Manipulation**: Strip whitespace from string fields if needed.
|
|
64
|
+
- **Casting**: Automatically cast values to the desired type.
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
You can install Statica via pip:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install statica
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Getting Started
|
|
75
|
+
|
|
76
|
+
### Basic Usage
|
|
77
|
+
|
|
78
|
+
Define a model with type annotations and constraints:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from statica.core import Statica, Field
|
|
82
|
+
|
|
83
|
+
class Payload(Statica):
|
|
84
|
+
name: str = Field(min_length=3, max_length=50, strip_whitespace=True)
|
|
85
|
+
description: str | None = Field(max_length=200)
|
|
86
|
+
num: int | float
|
|
87
|
+
float_num: float | None
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Instantiate the model using a dictionary:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
data = {
|
|
94
|
+
"name": "Test Payload",
|
|
95
|
+
"description": "A short description.",
|
|
96
|
+
"num": 42,
|
|
97
|
+
"float_num": 3.14,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
payload = Payload.from_map(data)
|
|
101
|
+
print(payload.name) # Output: "Test Payload"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or instantiate directly:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
payload = Payload(
|
|
108
|
+
name="Test",
|
|
109
|
+
description="This is a test description.",
|
|
110
|
+
num=42,
|
|
111
|
+
float_num=3.14,
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Validation
|
|
116
|
+
|
|
117
|
+
Statica automatically validates attributes based on type annotations and constraints:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from statica.core import ConstraintValidationError, TypeValidationError
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
payload = Payload(name="Te", description="Valid", num=42)
|
|
124
|
+
except ConstraintValidationError as e:
|
|
125
|
+
print(e) # Output: "name: length must be at least 3"
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
payload = Payload(name="Test", description="Valid", num="Invalid")
|
|
129
|
+
except TypeValidationError as e:
|
|
130
|
+
print(e) # Output: "num: expected type 'int | float', got 'str'"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Optional Fields
|
|
134
|
+
|
|
135
|
+
Fields annotated with `| None` are optional and default to `None`:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
class OptionalPayload(Statica):
|
|
139
|
+
name: str | None
|
|
140
|
+
|
|
141
|
+
payload = OptionalPayload()
|
|
142
|
+
print(payload.name) # Output: None
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Field Constraints
|
|
146
|
+
|
|
147
|
+
You can specify constraints on fields:
|
|
148
|
+
|
|
149
|
+
- **String Constraints**: `min_length`, `max_length`, `strip_whitespace`
|
|
150
|
+
- **Numeric Constraints**: `min_value`, `max_value`
|
|
151
|
+
- **Casting**: `cast_to`
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
class StringTest(Statica):
|
|
155
|
+
name: str = Field(min_length=3, max_length=5, strip_whitespace=True)
|
|
156
|
+
|
|
157
|
+
class IntTest(Statica):
|
|
158
|
+
num: int = Field(min_value=1, max_value=10, cast_to=int)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Custom Error Classes
|
|
162
|
+
|
|
163
|
+
You can define custom error classes for type and constraint validation:
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
class CustomError(Exception):
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
class CustomPayload(Statica):
|
|
170
|
+
constraint_error_class = CustomError
|
|
171
|
+
|
|
172
|
+
num: int = Field(min_value=1, max_value=10)
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
payload = CustomPayload(num=0)
|
|
176
|
+
except CustomError as e:
|
|
177
|
+
print(e) # Output: "num: must be at least 1"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Advanced Usage
|
|
181
|
+
|
|
182
|
+
### Short Syntax for Fields
|
|
183
|
+
|
|
184
|
+
You can use simple type annotations without explicitly defining `Field` descriptors:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
class ShortSyntax(Statica):
|
|
188
|
+
name: str
|
|
189
|
+
|
|
190
|
+
short = ShortSyntax(name="Test")
|
|
191
|
+
print(short.name) # Output: "Test"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Custom Initialization
|
|
195
|
+
|
|
196
|
+
Statica automatically generates an `__init__` method based on type annotations, ensuring that all required fields are provided during initialization.
|
|
197
|
+
|
|
198
|
+
### Casting
|
|
199
|
+
|
|
200
|
+
You can automatically cast input values to the desired type:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
class CastingExample(Statica):
|
|
204
|
+
num: int = Field(cast_to=int)
|
|
205
|
+
|
|
206
|
+
instance = CastingExample(num="42")
|
|
207
|
+
print(instance.num) # Output: 42
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Contributing
|
|
211
|
+
|
|
212
|
+
We welcome contributions to Statica! To contribute:
|
|
213
|
+
|
|
214
|
+
1. Fork the repository.
|
|
215
|
+
2. Create a new branch for your feature or bug fix.
|
|
216
|
+
3. Write tests for your changes.
|
|
217
|
+
4. Submit a pull request.
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
Statica is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
|
|
222
|
+
|
|
223
|
+
## Acknowledgments
|
|
224
|
+
|
|
225
|
+
Statica was built to simplify data validation and provide a robust and simple framework for type-safe models in Python, inspired by `pydantic` and `dataclasses`.
|
|
226
|
+
|
statica-1.0.2/README.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Statica
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Statica is a Python library for defining and validating structured data with type annotations and constraints. It provides an easy-to-use framework for creating type-safe models with comprehensive validation for both types and constraints.
|
|
8
|
+
|
|
9
|
+
## Why Statica?
|
|
10
|
+
|
|
11
|
+
Statica was created to address the need for a lightweight, flexible, and dependency-free alternative to libraries like pydantic.
|
|
12
|
+
While pydantic is a powerful tool for data validation and parsing, Statica offers some distinct advantages in specific situations:
|
|
13
|
+
|
|
14
|
+
1. **Lightweight**: Statica does not rely on any third-party dependencies, making it ideal for projects where minimizing external dependencies is a priority.
|
|
15
|
+
2. **Customizable Validation**: Statica allows fine-grained control over type and constraint validation through customizable field descriptors (`Field`) and error classes.
|
|
16
|
+
3. **Ease of Use**: With its simple, Pythonic design, Statica is intuitive for developers already familiar with Python's `dataclasses` and type hinting. It avoids much of the magic that pydantic employs.
|
|
17
|
+
4. **Performance**: For use cases where performance, especially memory usage, is critical, Statica avoids some of the overhead introduced by the advanced features of pydantic.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **Type Validation**: Automatically validates types for attributes based on type hints.
|
|
22
|
+
- **Constraint Validation**: Define constraints like minimum/maximum length, value ranges, and more.
|
|
23
|
+
- **Customizable Error Handling**: Use custom exception classes for type and constraint errors.
|
|
24
|
+
- **Flexible Field Descriptors**: Add constraints, casting, and other behaviors to your fields.
|
|
25
|
+
- **Optional Fields**: Support for optional fields with default values.
|
|
26
|
+
- **Automatic Initialization**: Automatically generate constructors (`__init__`) for your models.
|
|
27
|
+
- **String Manipulation**: Strip whitespace from string fields if needed.
|
|
28
|
+
- **Casting**: Automatically cast values to the desired type.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
You can install Statica via pip:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install statica
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Getting Started
|
|
39
|
+
|
|
40
|
+
### Basic Usage
|
|
41
|
+
|
|
42
|
+
Define a model with type annotations and constraints:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from statica.core import Statica, Field
|
|
46
|
+
|
|
47
|
+
class Payload(Statica):
|
|
48
|
+
name: str = Field(min_length=3, max_length=50, strip_whitespace=True)
|
|
49
|
+
description: str | None = Field(max_length=200)
|
|
50
|
+
num: int | float
|
|
51
|
+
float_num: float | None
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Instantiate the model using a dictionary:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
data = {
|
|
58
|
+
"name": "Test Payload",
|
|
59
|
+
"description": "A short description.",
|
|
60
|
+
"num": 42,
|
|
61
|
+
"float_num": 3.14,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
payload = Payload.from_map(data)
|
|
65
|
+
print(payload.name) # Output: "Test Payload"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or instantiate directly:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
payload = Payload(
|
|
72
|
+
name="Test",
|
|
73
|
+
description="This is a test description.",
|
|
74
|
+
num=42,
|
|
75
|
+
float_num=3.14,
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Validation
|
|
80
|
+
|
|
81
|
+
Statica automatically validates attributes based on type annotations and constraints:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from statica.core import ConstraintValidationError, TypeValidationError
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
payload = Payload(name="Te", description="Valid", num=42)
|
|
88
|
+
except ConstraintValidationError as e:
|
|
89
|
+
print(e) # Output: "name: length must be at least 3"
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
payload = Payload(name="Test", description="Valid", num="Invalid")
|
|
93
|
+
except TypeValidationError as e:
|
|
94
|
+
print(e) # Output: "num: expected type 'int | float', got 'str'"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Optional Fields
|
|
98
|
+
|
|
99
|
+
Fields annotated with `| None` are optional and default to `None`:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
class OptionalPayload(Statica):
|
|
103
|
+
name: str | None
|
|
104
|
+
|
|
105
|
+
payload = OptionalPayload()
|
|
106
|
+
print(payload.name) # Output: None
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Field Constraints
|
|
110
|
+
|
|
111
|
+
You can specify constraints on fields:
|
|
112
|
+
|
|
113
|
+
- **String Constraints**: `min_length`, `max_length`, `strip_whitespace`
|
|
114
|
+
- **Numeric Constraints**: `min_value`, `max_value`
|
|
115
|
+
- **Casting**: `cast_to`
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
class StringTest(Statica):
|
|
119
|
+
name: str = Field(min_length=3, max_length=5, strip_whitespace=True)
|
|
120
|
+
|
|
121
|
+
class IntTest(Statica):
|
|
122
|
+
num: int = Field(min_value=1, max_value=10, cast_to=int)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Custom Error Classes
|
|
126
|
+
|
|
127
|
+
You can define custom error classes for type and constraint validation:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
class CustomError(Exception):
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
class CustomPayload(Statica):
|
|
134
|
+
constraint_error_class = CustomError
|
|
135
|
+
|
|
136
|
+
num: int = Field(min_value=1, max_value=10)
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
payload = CustomPayload(num=0)
|
|
140
|
+
except CustomError as e:
|
|
141
|
+
print(e) # Output: "num: must be at least 1"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Advanced Usage
|
|
145
|
+
|
|
146
|
+
### Short Syntax for Fields
|
|
147
|
+
|
|
148
|
+
You can use simple type annotations without explicitly defining `Field` descriptors:
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
class ShortSyntax(Statica):
|
|
152
|
+
name: str
|
|
153
|
+
|
|
154
|
+
short = ShortSyntax(name="Test")
|
|
155
|
+
print(short.name) # Output: "Test"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Custom Initialization
|
|
159
|
+
|
|
160
|
+
Statica automatically generates an `__init__` method based on type annotations, ensuring that all required fields are provided during initialization.
|
|
161
|
+
|
|
162
|
+
### Casting
|
|
163
|
+
|
|
164
|
+
You can automatically cast input values to the desired type:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
class CastingExample(Statica):
|
|
168
|
+
num: int = Field(cast_to=int)
|
|
169
|
+
|
|
170
|
+
instance = CastingExample(num="42")
|
|
171
|
+
print(instance.num) # Output: 42
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Contributing
|
|
175
|
+
|
|
176
|
+
We welcome contributions to Statica! To contribute:
|
|
177
|
+
|
|
178
|
+
1. Fork the repository.
|
|
179
|
+
2. Create a new branch for your feature or bug fix.
|
|
180
|
+
3. Write tests for your changes.
|
|
181
|
+
4. Submit a pull request.
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
Statica is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
|
|
186
|
+
|
|
187
|
+
## Acknowledgments
|
|
188
|
+
|
|
189
|
+
Statica was built to simplify data validation and provide a robust and simple framework for type-safe models in Python, inspired by `pydantic` and `dataclasses`.
|
|
190
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "statica"
|
|
3
|
-
version = "1.0.
|
|
4
|
-
description = "
|
|
3
|
+
version = "1.0.2"
|
|
4
|
+
description = "A minimalistic data validation library"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Marcel Kröker", email = "kroeker.marcel@gmail.com" }]
|
|
7
7
|
license = { file = "LICENSE" }
|
|
@@ -57,6 +57,7 @@ line-length = 120
|
|
|
57
57
|
select = ["ALL"]
|
|
58
58
|
ignore = [
|
|
59
59
|
"ANN202", # Missing return type annotation for private function
|
|
60
|
+
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
|
|
60
61
|
"D", # docstrings
|
|
61
62
|
"E501", # line length
|
|
62
63
|
"ERA001", # Found commented-out code
|
|
@@ -71,6 +72,7 @@ ignore = [
|
|
|
71
72
|
"UP007", # use X | Y for union (not possible in python 3.8)
|
|
72
73
|
"UP035", # use typing Dict and List (not possible in python 3.8)
|
|
73
74
|
"W191", # indentation contains tabs
|
|
75
|
+
"PLR0913", # Too many arguments in function definition (6 > 5)
|
|
74
76
|
]
|
|
75
77
|
|
|
76
78
|
|
|
@@ -85,6 +87,7 @@ quote-style = "double"
|
|
|
85
87
|
[tool.coverage.report]
|
|
86
88
|
exclude_also = [
|
|
87
89
|
"if TYPE_CHECKING:",
|
|
90
|
+
'if __name__ == "__main__":',
|
|
88
91
|
]
|
|
89
92
|
|
|
90
93
|
|
|
@@ -6,6 +6,7 @@ from types import UnionType
|
|
|
6
6
|
from typing import (
|
|
7
7
|
TYPE_CHECKING,
|
|
8
8
|
Any,
|
|
9
|
+
Generic,
|
|
9
10
|
Self,
|
|
10
11
|
TypeVar,
|
|
11
12
|
cast,
|
|
@@ -16,26 +17,13 @@ from typing import (
|
|
|
16
17
|
overload,
|
|
17
18
|
)
|
|
18
19
|
|
|
20
|
+
from statica.exceptions import ConstraintValidationError, TypeValidationError
|
|
21
|
+
|
|
19
22
|
if TYPE_CHECKING:
|
|
20
23
|
from collections.abc import Callable, Mapping
|
|
21
24
|
|
|
22
25
|
T = TypeVar("T")
|
|
23
26
|
|
|
24
|
-
########################################################################################
|
|
25
|
-
#### MARK: Exceptions
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class ValidationError(Exception):
|
|
29
|
-
"""Base validation error."""
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class TypeValidationError(ValidationError):
|
|
33
|
-
"""Raised when type validation fails."""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class ConstraintValidationError(ValidationError):
|
|
37
|
-
"""Raised when constraint validation fails."""
|
|
38
|
-
|
|
39
27
|
|
|
40
28
|
########################################################################################
|
|
41
29
|
#### MARK: Internal functions
|
|
@@ -131,7 +119,7 @@ def _get_expected_type(cls: type, attr_name: str) -> Any:
|
|
|
131
119
|
|
|
132
120
|
|
|
133
121
|
@dataclass
|
|
134
|
-
class FieldDescriptor[T]:
|
|
122
|
+
class FieldDescriptor(Generic[T]):
|
|
135
123
|
"""
|
|
136
124
|
Descriptor for validated fields.
|
|
137
125
|
"""
|
|
@@ -240,7 +228,7 @@ def Field( # noqa: N802
|
|
|
240
228
|
)
|
|
241
229
|
|
|
242
230
|
if TYPE_CHECKING:
|
|
243
|
-
return cast(Any, fd)
|
|
231
|
+
return cast("Any", fd)
|
|
244
232
|
|
|
245
233
|
return fd # type: ignore[unreachable]
|
|
246
234
|
|
|
@@ -251,6 +239,9 @@ def Field( # noqa: N802
|
|
|
251
239
|
|
|
252
240
|
@dataclass_transform(kw_only_default=True)
|
|
253
241
|
class StaticaMeta(type):
|
|
242
|
+
type_error_class: type[Exception] = TypeValidationError
|
|
243
|
+
constraint_error_class: type[Exception] = ConstraintValidationError
|
|
244
|
+
|
|
254
245
|
def __new__(cls, name: str, bases: tuple, namespace: dict[str, Any]) -> type:
|
|
255
246
|
"""
|
|
256
247
|
Set up Field descriptors for each type-hinted attribute which does not have one
|
|
@@ -303,9 +294,6 @@ class StaticaMeta(type):
|
|
|
303
294
|
|
|
304
295
|
|
|
305
296
|
class Statica(metaclass=StaticaMeta):
|
|
306
|
-
type_error_class: type[Exception] = TypeValidationError
|
|
307
|
-
constraint_error_class: type[Exception] = ConstraintValidationError
|
|
308
|
-
|
|
309
297
|
@classmethod
|
|
310
298
|
def from_map(cls, mapping: Mapping[str, Any]) -> Self:
|
|
311
299
|
instance = cls(**mapping)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class ValidationError(Exception):
|
|
2
|
+
"""Base validation error."""
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TypeValidationError(ValidationError):
|
|
6
|
+
"""Raised when type validation fails."""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConstraintValidationError(ValidationError):
|
|
10
|
+
"""Raised when constraint validation fails."""
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: statica
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: A minimalistic data validation library
|
|
5
|
+
Author-email: Marcel Kröker <kroeker.marcel@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 mkrd
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Classifier: Programming Language :: Python :: 3
|
|
29
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
30
|
+
Classifier: Operating System :: OS Independent
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: Programming Language :: Python
|
|
33
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
34
|
+
Requires-Python: <3.14,>=3.11
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# Statica
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
Statica is a Python library for defining and validating structured data with type annotations and constraints. It provides an easy-to-use framework for creating type-safe models with comprehensive validation for both types and constraints.
|
|
44
|
+
|
|
45
|
+
## Why Statica?
|
|
46
|
+
|
|
47
|
+
Statica was created to address the need for a lightweight, flexible, and dependency-free alternative to libraries like pydantic.
|
|
48
|
+
While pydantic is a powerful tool for data validation and parsing, Statica offers some distinct advantages in specific situations:
|
|
49
|
+
|
|
50
|
+
1. **Lightweight**: Statica does not rely on any third-party dependencies, making it ideal for projects where minimizing external dependencies is a priority.
|
|
51
|
+
2. **Customizable Validation**: Statica allows fine-grained control over type and constraint validation through customizable field descriptors (`Field`) and error classes.
|
|
52
|
+
3. **Ease of Use**: With its simple, Pythonic design, Statica is intuitive for developers already familiar with Python's `dataclasses` and type hinting. It avoids much of the magic that pydantic employs.
|
|
53
|
+
4. **Performance**: For use cases where performance, especially memory usage, is critical, Statica avoids some of the overhead introduced by the advanced features of pydantic.
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
- **Type Validation**: Automatically validates types for attributes based on type hints.
|
|
58
|
+
- **Constraint Validation**: Define constraints like minimum/maximum length, value ranges, and more.
|
|
59
|
+
- **Customizable Error Handling**: Use custom exception classes for type and constraint errors.
|
|
60
|
+
- **Flexible Field Descriptors**: Add constraints, casting, and other behaviors to your fields.
|
|
61
|
+
- **Optional Fields**: Support for optional fields with default values.
|
|
62
|
+
- **Automatic Initialization**: Automatically generate constructors (`__init__`) for your models.
|
|
63
|
+
- **String Manipulation**: Strip whitespace from string fields if needed.
|
|
64
|
+
- **Casting**: Automatically cast values to the desired type.
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
You can install Statica via pip:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install statica
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Getting Started
|
|
75
|
+
|
|
76
|
+
### Basic Usage
|
|
77
|
+
|
|
78
|
+
Define a model with type annotations and constraints:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from statica.core import Statica, Field
|
|
82
|
+
|
|
83
|
+
class Payload(Statica):
|
|
84
|
+
name: str = Field(min_length=3, max_length=50, strip_whitespace=True)
|
|
85
|
+
description: str | None = Field(max_length=200)
|
|
86
|
+
num: int | float
|
|
87
|
+
float_num: float | None
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Instantiate the model using a dictionary:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
data = {
|
|
94
|
+
"name": "Test Payload",
|
|
95
|
+
"description": "A short description.",
|
|
96
|
+
"num": 42,
|
|
97
|
+
"float_num": 3.14,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
payload = Payload.from_map(data)
|
|
101
|
+
print(payload.name) # Output: "Test Payload"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or instantiate directly:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
payload = Payload(
|
|
108
|
+
name="Test",
|
|
109
|
+
description="This is a test description.",
|
|
110
|
+
num=42,
|
|
111
|
+
float_num=3.14,
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Validation
|
|
116
|
+
|
|
117
|
+
Statica automatically validates attributes based on type annotations and constraints:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from statica.core import ConstraintValidationError, TypeValidationError
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
payload = Payload(name="Te", description="Valid", num=42)
|
|
124
|
+
except ConstraintValidationError as e:
|
|
125
|
+
print(e) # Output: "name: length must be at least 3"
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
payload = Payload(name="Test", description="Valid", num="Invalid")
|
|
129
|
+
except TypeValidationError as e:
|
|
130
|
+
print(e) # Output: "num: expected type 'int | float', got 'str'"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Optional Fields
|
|
134
|
+
|
|
135
|
+
Fields annotated with `| None` are optional and default to `None`:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
class OptionalPayload(Statica):
|
|
139
|
+
name: str | None
|
|
140
|
+
|
|
141
|
+
payload = OptionalPayload()
|
|
142
|
+
print(payload.name) # Output: None
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Field Constraints
|
|
146
|
+
|
|
147
|
+
You can specify constraints on fields:
|
|
148
|
+
|
|
149
|
+
- **String Constraints**: `min_length`, `max_length`, `strip_whitespace`
|
|
150
|
+
- **Numeric Constraints**: `min_value`, `max_value`
|
|
151
|
+
- **Casting**: `cast_to`
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
class StringTest(Statica):
|
|
155
|
+
name: str = Field(min_length=3, max_length=5, strip_whitespace=True)
|
|
156
|
+
|
|
157
|
+
class IntTest(Statica):
|
|
158
|
+
num: int = Field(min_value=1, max_value=10, cast_to=int)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Custom Error Classes
|
|
162
|
+
|
|
163
|
+
You can define custom error classes for type and constraint validation:
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
class CustomError(Exception):
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
class CustomPayload(Statica):
|
|
170
|
+
constraint_error_class = CustomError
|
|
171
|
+
|
|
172
|
+
num: int = Field(min_value=1, max_value=10)
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
payload = CustomPayload(num=0)
|
|
176
|
+
except CustomError as e:
|
|
177
|
+
print(e) # Output: "num: must be at least 1"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Advanced Usage
|
|
181
|
+
|
|
182
|
+
### Short Syntax for Fields
|
|
183
|
+
|
|
184
|
+
You can use simple type annotations without explicitly defining `Field` descriptors:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
class ShortSyntax(Statica):
|
|
188
|
+
name: str
|
|
189
|
+
|
|
190
|
+
short = ShortSyntax(name="Test")
|
|
191
|
+
print(short.name) # Output: "Test"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Custom Initialization
|
|
195
|
+
|
|
196
|
+
Statica automatically generates an `__init__` method based on type annotations, ensuring that all required fields are provided during initialization.
|
|
197
|
+
|
|
198
|
+
### Casting
|
|
199
|
+
|
|
200
|
+
You can automatically cast input values to the desired type:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
class CastingExample(Statica):
|
|
204
|
+
num: int = Field(cast_to=int)
|
|
205
|
+
|
|
206
|
+
instance = CastingExample(num="42")
|
|
207
|
+
print(instance.num) # Output: 42
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Contributing
|
|
211
|
+
|
|
212
|
+
We welcome contributions to Statica! To contribute:
|
|
213
|
+
|
|
214
|
+
1. Fork the repository.
|
|
215
|
+
2. Create a new branch for your feature or bug fix.
|
|
216
|
+
3. Write tests for your changes.
|
|
217
|
+
4. Submit a pull request.
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
Statica is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
|
|
222
|
+
|
|
223
|
+
## Acknowledgments
|
|
224
|
+
|
|
225
|
+
Statica was built to simplify data validation and provide a robust and simple framework for type-safe models in Python, inspired by `pydantic` and `dataclasses`.
|
|
226
|
+
|
statica-1.0.0/PKG-INFO
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: statica
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Minimalistic validation library for Python 3.11+
|
|
5
|
-
Author-email: Marcel Kröker <kroeker.marcel@gmail.com>
|
|
6
|
-
License: MIT License
|
|
7
|
-
|
|
8
|
-
Copyright (c) 2025 mkrd
|
|
9
|
-
|
|
10
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
-
in the Software without restriction, including without limitation the rights
|
|
13
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
-
furnished to do so, subject to the following conditions:
|
|
16
|
-
|
|
17
|
-
The above copyright notice and this permission notice shall be included in all
|
|
18
|
-
copies or substantial portions of the Software.
|
|
19
|
-
|
|
20
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
-
SOFTWARE.
|
|
27
|
-
|
|
28
|
-
Classifier: Programming Language :: Python :: 3
|
|
29
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
30
|
-
Classifier: Operating System :: OS Independent
|
|
31
|
-
Classifier: Intended Audience :: Developers
|
|
32
|
-
Classifier: Programming Language :: Python
|
|
33
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
34
|
-
Requires-Python: <3.14,>=3.11
|
|
35
|
-
Description-Content-Type: text/markdown
|
|
36
|
-
|
|
37
|
-
# Statica
|
|
38
|
-
A minimalistic data validation library.
|
statica-1.0.0/README.md
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: statica
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Minimalistic validation library for Python 3.11+
|
|
5
|
-
Author-email: Marcel Kröker <kroeker.marcel@gmail.com>
|
|
6
|
-
License: MIT License
|
|
7
|
-
|
|
8
|
-
Copyright (c) 2025 mkrd
|
|
9
|
-
|
|
10
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
-
in the Software without restriction, including without limitation the rights
|
|
13
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
-
furnished to do so, subject to the following conditions:
|
|
16
|
-
|
|
17
|
-
The above copyright notice and this permission notice shall be included in all
|
|
18
|
-
copies or substantial portions of the Software.
|
|
19
|
-
|
|
20
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
-
SOFTWARE.
|
|
27
|
-
|
|
28
|
-
Classifier: Programming Language :: Python :: 3
|
|
29
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
30
|
-
Classifier: Operating System :: OS Independent
|
|
31
|
-
Classifier: Intended Audience :: Developers
|
|
32
|
-
Classifier: Programming Language :: Python
|
|
33
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
34
|
-
Requires-Python: <3.14,>=3.11
|
|
35
|
-
Description-Content-Type: text/markdown
|
|
36
|
-
|
|
37
|
-
# Statica
|
|
38
|
-
A minimalistic data validation library.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|