statica 1.3.0__tar.gz → 1.6.0__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.
@@ -1,44 +1,44 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.3
2
2
  Name: statica
3
- Version: 1.3.0
3
+ Version: 1.6.0
4
4
  Summary: A minimalistic data validation library
5
+ Author: Marcel Kröker
5
6
  Author-email: Marcel Kröker <kroeker.marcel@gmail.com>
6
7
  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
-
8
+
9
+ Copyright (c) 2025 mkrd
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
28
  Classifier: Programming Language :: Python :: 3
29
29
  Classifier: License :: OSI Approved :: MIT License
30
30
  Classifier: Operating System :: OS Independent
31
31
  Classifier: Intended Audience :: Developers
32
32
  Classifier: Programming Language :: Python
33
33
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
34
- Requires-Python: <3.14,>=3.11
34
+ Requires-Python: >=3.11, <3.15
35
35
  Description-Content-Type: text/markdown
36
36
 
37
37
  Statica
38
38
  ========================================================================================
39
39
 
40
- ![Tests](https://github.com/mkrd/statica/actions/workflows/test.yml/badge.svg)
41
- ![Coverage](https://github.com/mkrd/statica/blob/main/assets/coverage.svg?raw=true)
40
+ ![Tests](https://git.budgetflow.cc/mkrd/statica/actions/workflows/test.yml/badge.svg)
41
+ ![Coverage](https://git.budgetflow.cc/mkrd/statica/raw/branch/main/assets/coverage.svg)
42
42
 
43
43
 
44
44
  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.
@@ -47,7 +47,7 @@ Statica is a Python library for defining and validating structured data with typ
47
47
  Why Statica?
48
48
  ----------------------------------------------------------------------------------------
49
49
 
50
- Statica was created to address the need for a lightweight, flexible, and dependency-free alternative to libraries like Pydantic.
50
+ Statica was created to address the need for a lightweight, flexible, and dependency-free alternative to Pydantic.
51
51
  While pydantic is a powerful tool for data validation and parsing, Statica offers some distinct advantages in specific situations:
52
52
 
53
53
  1. **Lightweight**: Statica has zero dependencies, making it ideal for projects where minimizing external dependencies is a priority.
@@ -61,6 +61,7 @@ Features
61
61
 
62
62
  - **Type Validation**: Automatically validates types for attributes based on type hints.
63
63
  - **Constraint Validation**: Define constraints like minimum/maximum length, value ranges, and more.
64
+ - **Default Field Values**: Set default values for fields that are used when not explicitly provided.
64
65
  - **Customizable Error Handling**: Use custom exception classes for type and constraint errors.
65
66
  - **Flexible Field Descriptors**: Add constraints, casting, and other behaviors to your fields.
66
67
  - **Optional Fields**: Support for optional fields with default values.
@@ -152,13 +153,92 @@ payload = OptionalPayload()
152
153
  print(payload.name) # Output: None
153
154
  ```
154
155
 
156
+ ### Default Field Values
157
+
158
+ You can specify default values for fields in two ways:
159
+
160
+ #### Using Field() with default parameter
161
+
162
+ ```python
163
+ class User(Statica):
164
+ name: str
165
+ age: int = Field(default=25)
166
+ active: bool = Field(default=True)
167
+
168
+ # Using direct initialization
169
+ user = User(name="John")
170
+ print(user.name) # Output: "John"
171
+ print(user.age) # Output: 25
172
+ print(user.active) # Output: True
173
+
174
+ # Using from_map
175
+ user = User.from_map({"name": "Jane"})
176
+ print(user.age) # Output: 25 (default used)
177
+
178
+ # Explicit values override defaults
179
+ user = User(name="Bob", age=30, active=False)
180
+ print(user.age) # Output: 30
181
+ ```
182
+
183
+ #### Direct assignment (without Field)
184
+
185
+ You can also assign default values directly to fields without using `Field()`:
186
+
187
+ ```python
188
+ class Config(Statica):
189
+ name: str
190
+ timeout: float = 30.0 # Direct assignment
191
+ retries: int = 3 # Direct assignment
192
+ debug: bool = False # Direct assignment
193
+
194
+ config = Config(name="server")
195
+ print(config.timeout) # Output: 30.0
196
+ print(config.retries) # Output: 3
197
+ print(config.debug) # Output: False
198
+
199
+ # Works with from_map too
200
+ config = Config.from_map({"name": "api-server"})
201
+ print(config.timeout) # Output: 30.0 (default used)
202
+ ```
203
+
204
+ Both approaches work identically and can be mixed within the same class. Use `Field(default=...)` when you need additional constraints or options, and direct assignment for simple defaults.
205
+
206
+ #### Validation and Safety
207
+
208
+ Default values are validated against any constraints you've defined:
209
+
210
+ ```python
211
+ class Config(Statica):
212
+ timeout: float = Field(default=30.0, min_value=1.0, max_value=120.0)
213
+ retries: int = Field(default=3, min_value=1)
214
+
215
+ config = Config() # Uses defaults: timeout=30.0, retries=3
216
+ ```
217
+
218
+ For mutable default values (like lists, dicts, sets), Statica automatically creates copies to prevent shared state issues:
219
+
220
+ ```python
221
+ class UserProfile(Statica):
222
+ name: str
223
+ tags: list[str] = Field(default=[]) # or tags: list[str] = []
224
+
225
+ user1 = UserProfile(name="Alice")
226
+ user2 = UserProfile(name="Bob")
227
+
228
+ user1.tags.append("admin")
229
+ print(user1.tags) # Output: ["admin"]
230
+ print(user2.tags) # Output: [] (not affected)
231
+ ```
232
+
155
233
  ### Field Constraints
156
234
 
157
- You can specify constraints on fields:
235
+ You can specify constraints and options on fields:
158
236
 
237
+ - **Default Values**: `default` (using `Field()`) or direct assignment
159
238
  - **String Constraints**: `min_length`, `max_length`, `strip_whitespace`
160
239
  - **Numeric Constraints**: `min_value`, `max_value`
161
240
  - **Casting**: `cast_to`
241
+ - **Aliasing**: `alias`
162
242
 
163
243
  ```python
164
244
  class StringTest(Statica):
@@ -166,6 +246,15 @@ class StringTest(Statica):
166
246
 
167
247
  class IntTest(Statica):
168
248
  num: int = Field(min_value=1, max_value=10, cast_to=int)
249
+
250
+ class DefaultTest(Statica):
251
+ # Using Field() for defaults with constraints
252
+ status: str = Field(default="active")
253
+ priority: int = Field(default=1, min_value=1, max_value=5)
254
+
255
+ # Direct assignment for simple defaults
256
+ timeout: float = 30.0
257
+ retries: int = 3
169
258
  ```
170
259
 
171
260
  ### Custom Error Classes
@@ -212,68 +301,27 @@ Aliasing
212
301
  Statica supports field aliasing, allowing you to map different field names for parsing and serialization.
213
302
  This is particularly useful when working with external APIs that use different naming conventions.
214
303
 
215
- ### Basic Aliases
216
-
217
304
  Use the `alias` parameter to define an alternative name for both parsing and serialization:
218
305
 
219
306
  ```python
220
307
  class User(Statica):
221
308
  full_name: str = Field(alias="fullName")
222
- age: int = Field(alias="userAge")
309
+ age: int = Field(alias="userAge", default=25)
223
310
 
224
311
  # Parse data with aliases
225
- data = {"fullName": "John Doe", "userAge": 30}
312
+ data = {"fullName": "John Doe"} # userAge not provided, uses default
226
313
  user = User.from_map(data)
227
314
  print(user.full_name) # Output: "John Doe"
228
- print(user.age) # Output: 30
315
+ print(user.age) # Output: 25
229
316
 
230
- # Serialize back with aliases
317
+ # Serialize back with aliases (uses the alias for serialization by default)
231
318
  result = user.to_dict()
232
- print(result) # Output: {"fullName": "John Doe", "userAge": 30}
233
- ```
234
-
235
- ### Separate Parsing and Serialization Aliases
319
+ print(result) # Output: {"fullName": "John Doe", "userAge": 25}
236
320
 
237
- You can define different aliases for parsing and serialization:
321
+ # Serialize without aliases
322
+ result_no_alias = user.to_dict(with_aliases=False)
323
+ print(result_no_alias) # Output: {"full_name": "John Doe", "age": 25}
238
324
 
239
- ```python
240
- class APIModel(Statica):
241
- user_name: str = Field(
242
- alias_for_parsing="userName",
243
- alias_for_serialization="username"
244
- )
245
- user_id: int = Field(alias_for_parsing="userId")
246
-
247
- # Parse from camelCase API response
248
- api_data = {"userName": "alice", "userId": 123}
249
- model = APIModel.from_map(api_data)
250
-
251
- # Serialize to snake_case for internal use
252
- internal_data = model.to_dict()
253
- print(internal_data) # Output: {"username": "alice", "user_id": 123}
254
- ```
255
-
256
- ### Alias Priority
257
-
258
- When multiple alias types are defined, the priority is:
259
- 1. `alias_for_parsing` for parsing operations
260
- 2. `alias_for_serialization` for serialization operations
261
- 3. `alias` as a fallback for both operations
262
-
263
- ```python
264
- class PriorityExample(Statica):
265
- field_name: str = Field(
266
- alias="generalAlias",
267
- alias_for_parsing="parseAlias",
268
- alias_for_serialization="serializeAlias"
269
- )
270
-
271
- # Uses alias_for_parsing
272
- instance = PriorityExample.from_map({"parseAlias": "value"})
273
-
274
- # Uses alias_for_serialization
275
- result = instance.to_dict()
276
- print(result) # Output: {"serializeAlias": "value"}
277
325
  ```
278
326
 
279
327
  Advanced Usage
@@ -296,6 +344,12 @@ print(instance.num) # Output: 42
296
344
  ```
297
345
 
298
346
 
347
+ Design Decisions
348
+ ----------------------------------------------------------------------------------------
349
+
350
+ - [Inheritance over Decorators](docs/decision-inheritance-over-decorators.md)
351
+
352
+
299
353
  Contributing
300
354
  ----------------------------------------------------------------------------------------
301
355
 
@@ -1,44 +1,8 @@
1
- Metadata-Version: 2.4
2
- Name: statica
3
- Version: 1.3.0
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
1
  Statica
38
2
  ========================================================================================
39
3
 
40
- ![Tests](https://github.com/mkrd/statica/actions/workflows/test.yml/badge.svg)
41
- ![Coverage](https://github.com/mkrd/statica/blob/main/assets/coverage.svg?raw=true)
4
+ ![Tests](https://git.budgetflow.cc/mkrd/statica/actions/workflows/test.yml/badge.svg)
5
+ ![Coverage](https://git.budgetflow.cc/mkrd/statica/raw/branch/main/assets/coverage.svg)
42
6
 
43
7
 
44
8
  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.
@@ -47,7 +11,7 @@ Statica is a Python library for defining and validating structured data with typ
47
11
  Why Statica?
48
12
  ----------------------------------------------------------------------------------------
49
13
 
50
- Statica was created to address the need for a lightweight, flexible, and dependency-free alternative to libraries like Pydantic.
14
+ Statica was created to address the need for a lightweight, flexible, and dependency-free alternative to Pydantic.
51
15
  While pydantic is a powerful tool for data validation and parsing, Statica offers some distinct advantages in specific situations:
52
16
 
53
17
  1. **Lightweight**: Statica has zero dependencies, making it ideal for projects where minimizing external dependencies is a priority.
@@ -61,6 +25,7 @@ Features
61
25
 
62
26
  - **Type Validation**: Automatically validates types for attributes based on type hints.
63
27
  - **Constraint Validation**: Define constraints like minimum/maximum length, value ranges, and more.
28
+ - **Default Field Values**: Set default values for fields that are used when not explicitly provided.
64
29
  - **Customizable Error Handling**: Use custom exception classes for type and constraint errors.
65
30
  - **Flexible Field Descriptors**: Add constraints, casting, and other behaviors to your fields.
66
31
  - **Optional Fields**: Support for optional fields with default values.
@@ -152,13 +117,92 @@ payload = OptionalPayload()
152
117
  print(payload.name) # Output: None
153
118
  ```
154
119
 
120
+ ### Default Field Values
121
+
122
+ You can specify default values for fields in two ways:
123
+
124
+ #### Using Field() with default parameter
125
+
126
+ ```python
127
+ class User(Statica):
128
+ name: str
129
+ age: int = Field(default=25)
130
+ active: bool = Field(default=True)
131
+
132
+ # Using direct initialization
133
+ user = User(name="John")
134
+ print(user.name) # Output: "John"
135
+ print(user.age) # Output: 25
136
+ print(user.active) # Output: True
137
+
138
+ # Using from_map
139
+ user = User.from_map({"name": "Jane"})
140
+ print(user.age) # Output: 25 (default used)
141
+
142
+ # Explicit values override defaults
143
+ user = User(name="Bob", age=30, active=False)
144
+ print(user.age) # Output: 30
145
+ ```
146
+
147
+ #### Direct assignment (without Field)
148
+
149
+ You can also assign default values directly to fields without using `Field()`:
150
+
151
+ ```python
152
+ class Config(Statica):
153
+ name: str
154
+ timeout: float = 30.0 # Direct assignment
155
+ retries: int = 3 # Direct assignment
156
+ debug: bool = False # Direct assignment
157
+
158
+ config = Config(name="server")
159
+ print(config.timeout) # Output: 30.0
160
+ print(config.retries) # Output: 3
161
+ print(config.debug) # Output: False
162
+
163
+ # Works with from_map too
164
+ config = Config.from_map({"name": "api-server"})
165
+ print(config.timeout) # Output: 30.0 (default used)
166
+ ```
167
+
168
+ Both approaches work identically and can be mixed within the same class. Use `Field(default=...)` when you need additional constraints or options, and direct assignment for simple defaults.
169
+
170
+ #### Validation and Safety
171
+
172
+ Default values are validated against any constraints you've defined:
173
+
174
+ ```python
175
+ class Config(Statica):
176
+ timeout: float = Field(default=30.0, min_value=1.0, max_value=120.0)
177
+ retries: int = Field(default=3, min_value=1)
178
+
179
+ config = Config() # Uses defaults: timeout=30.0, retries=3
180
+ ```
181
+
182
+ For mutable default values (like lists, dicts, sets), Statica automatically creates copies to prevent shared state issues:
183
+
184
+ ```python
185
+ class UserProfile(Statica):
186
+ name: str
187
+ tags: list[str] = Field(default=[]) # or tags: list[str] = []
188
+
189
+ user1 = UserProfile(name="Alice")
190
+ user2 = UserProfile(name="Bob")
191
+
192
+ user1.tags.append("admin")
193
+ print(user1.tags) # Output: ["admin"]
194
+ print(user2.tags) # Output: [] (not affected)
195
+ ```
196
+
155
197
  ### Field Constraints
156
198
 
157
- You can specify constraints on fields:
199
+ You can specify constraints and options on fields:
158
200
 
201
+ - **Default Values**: `default` (using `Field()`) or direct assignment
159
202
  - **String Constraints**: `min_length`, `max_length`, `strip_whitespace`
160
203
  - **Numeric Constraints**: `min_value`, `max_value`
161
204
  - **Casting**: `cast_to`
205
+ - **Aliasing**: `alias`
162
206
 
163
207
  ```python
164
208
  class StringTest(Statica):
@@ -166,6 +210,15 @@ class StringTest(Statica):
166
210
 
167
211
  class IntTest(Statica):
168
212
  num: int = Field(min_value=1, max_value=10, cast_to=int)
213
+
214
+ class DefaultTest(Statica):
215
+ # Using Field() for defaults with constraints
216
+ status: str = Field(default="active")
217
+ priority: int = Field(default=1, min_value=1, max_value=5)
218
+
219
+ # Direct assignment for simple defaults
220
+ timeout: float = 30.0
221
+ retries: int = 3
169
222
  ```
170
223
 
171
224
  ### Custom Error Classes
@@ -212,68 +265,27 @@ Aliasing
212
265
  Statica supports field aliasing, allowing you to map different field names for parsing and serialization.
213
266
  This is particularly useful when working with external APIs that use different naming conventions.
214
267
 
215
- ### Basic Aliases
216
-
217
268
  Use the `alias` parameter to define an alternative name for both parsing and serialization:
218
269
 
219
270
  ```python
220
271
  class User(Statica):
221
272
  full_name: str = Field(alias="fullName")
222
- age: int = Field(alias="userAge")
273
+ age: int = Field(alias="userAge", default=25)
223
274
 
224
275
  # Parse data with aliases
225
- data = {"fullName": "John Doe", "userAge": 30}
276
+ data = {"fullName": "John Doe"} # userAge not provided, uses default
226
277
  user = User.from_map(data)
227
278
  print(user.full_name) # Output: "John Doe"
228
- print(user.age) # Output: 30
279
+ print(user.age) # Output: 25
229
280
 
230
- # Serialize back with aliases
281
+ # Serialize back with aliases (uses the alias for serialization by default)
231
282
  result = user.to_dict()
232
- print(result) # Output: {"fullName": "John Doe", "userAge": 30}
233
- ```
234
-
235
- ### Separate Parsing and Serialization Aliases
283
+ print(result) # Output: {"fullName": "John Doe", "userAge": 25}
236
284
 
237
- You can define different aliases for parsing and serialization:
285
+ # Serialize without aliases
286
+ result_no_alias = user.to_dict(with_aliases=False)
287
+ print(result_no_alias) # Output: {"full_name": "John Doe", "age": 25}
238
288
 
239
- ```python
240
- class APIModel(Statica):
241
- user_name: str = Field(
242
- alias_for_parsing="userName",
243
- alias_for_serialization="username"
244
- )
245
- user_id: int = Field(alias_for_parsing="userId")
246
-
247
- # Parse from camelCase API response
248
- api_data = {"userName": "alice", "userId": 123}
249
- model = APIModel.from_map(api_data)
250
-
251
- # Serialize to snake_case for internal use
252
- internal_data = model.to_dict()
253
- print(internal_data) # Output: {"username": "alice", "user_id": 123}
254
- ```
255
-
256
- ### Alias Priority
257
-
258
- When multiple alias types are defined, the priority is:
259
- 1. `alias_for_parsing` for parsing operations
260
- 2. `alias_for_serialization` for serialization operations
261
- 3. `alias` as a fallback for both operations
262
-
263
- ```python
264
- class PriorityExample(Statica):
265
- field_name: str = Field(
266
- alias="generalAlias",
267
- alias_for_parsing="parseAlias",
268
- alias_for_serialization="serializeAlias"
269
- )
270
-
271
- # Uses alias_for_parsing
272
- instance = PriorityExample.from_map({"parseAlias": "value"})
273
-
274
- # Uses alias_for_serialization
275
- result = instance.to_dict()
276
- print(result) # Output: {"serializeAlias": "value"}
277
289
  ```
278
290
 
279
291
  Advanced Usage
@@ -296,6 +308,12 @@ print(instance.num) # Output: 42
296
308
  ```
297
309
 
298
310
 
311
+ Design Decisions
312
+ ----------------------------------------------------------------------------------------
313
+
314
+ - [Inheritance over Decorators](docs/decision-inheritance-over-decorators.md)
315
+
316
+
299
317
  Contributing
300
318
  ----------------------------------------------------------------------------------------
301
319
 
@@ -1,48 +1,47 @@
1
1
  [project]
2
2
  name = "statica"
3
- version = "1.3.0"
3
+ version = "1.6.0"
4
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" }
8
- classifiers=[
8
+ classifiers = [
9
9
  "Programming Language :: Python :: 3",
10
10
  "License :: OSI Approved :: MIT License",
11
11
  "Operating System :: OS Independent",
12
12
  "Intended Audience :: Developers",
13
13
  "Programming Language :: Python",
14
- "Topic :: Software Development :: Libraries :: Python Modules"
14
+ "Topic :: Software Development :: Libraries :: Python Modules",
15
15
  ]
16
- requires-python = ">=3.11, <3.14"
17
16
 
18
17
 
19
18
  ########################################################################################
20
19
  #### MARK: Dependencies
21
20
 
22
21
 
23
- dependencies = []
22
+ requires-python = ">=3.11, <3.15"
24
23
 
24
+ dependencies = []
25
25
 
26
26
  [dependency-groups]
27
27
  dev = [
28
- "mypy ~= 1.16.0",
29
- "pyinstrument>=5.0.2",
30
- "pytest-cov ~= 6.1.0",
31
- "ruff ~= 0.11.0",
28
+ "pyrefly ~= 1.1.0",
29
+ "pyinstrument ~= 5.1.0",
30
+ "pytest-cov ~= 7.1.0",
31
+ "ruff ~= 0.15.0",
32
32
  ]
33
33
 
34
34
 
35
35
  ########################################################################################
36
- #### MARK: Packaging
37
-
36
+ #### MARK: Build System
38
37
 
39
- [tool.setuptools]
40
- packages = ["statica"]
41
- license-files = [] # Workaround for https://github.com/astral-sh/uv/issues/9513
42
38
 
39
+ [build-system]
40
+ requires = ["uv_build>=0.11.32,<0.12.0"]
41
+ build-backend = "uv_build"
43
42
 
44
- [tool.uv]
45
- package = true
43
+ [tool.uv.build-backend]
44
+ module-root = ""
46
45
 
47
46
 
48
47
  ########################################################################################
@@ -53,22 +52,21 @@ package = true
53
52
  show-fixes = true
54
53
  line-length = 100
55
54
 
56
-
57
55
  [tool.ruff.lint]
58
56
  select = ["ALL"]
59
57
  ignore = [
60
58
  "ANN202", # Missing return type annotation for private function
61
59
  "ANN401", # Dynamically typed expressions (typing.Any) are disallowed
60
+ "COM812", # Missing trailing comma
62
61
  "D", # docstrings
63
62
  "ERA001", # Found commented-out code
64
63
  "INP001", # File is part of an implicit namespace package. Add an `__init__.py`.
64
+ "PLR0913", # Too many arguments in function definition (6 > 5)
65
65
  "S101", # Use of `assert` detected
66
66
  "T201", # `print` found
67
67
  "W191", # indentation contains tabs
68
- "PLR0913", # Too many arguments in function definition (6 > 5)
69
68
  ]
70
69
 
71
-
72
70
  [tool.ruff.format]
73
71
  indent-style = "tab"
74
72
  quote-style = "double"
@@ -77,6 +75,7 @@ quote-style = "double"
77
75
  ########################################################################################
78
76
  #### MARK: Testing
79
77
 
78
+
80
79
  [tool.coverage.report]
81
80
  omit = [
82
81
  "benchmark_*.py",
@@ -88,7 +87,9 @@ exclude_also = [
88
87
 
89
88
 
90
89
  ########################################################################################
91
- #### MARK: Mypy
90
+ #### MARK: Pyrefly
91
+
92
92
 
93
- [tool.mypy]
94
- ignore_missing_imports = true
93
+ [tool.pyrefly]
94
+ preset = "strict"
95
+ min-severity = "warn"
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class StaticaConfig:
8
+ type_error_message: str
9
+ min_length_error_message: str
10
+ max_length_error_message: str
11
+ min_value_error_message: str
12
+ max_value_error_message: str
13
+
14
+ @classmethod
15
+ def create(
16
+ cls,
17
+ *,
18
+ type_error_message: str = "expected type '{expected_type}', got '{found_type}'",
19
+ min_length_error_message: str = "{field_name} length must be at least {min_length}",
20
+ max_length_error_message: str = "{field_name} length must be at most {max_length}",
21
+ min_value_error_message: str = "{field_name} must be at least {min_value}",
22
+ max_value_error_message: str = "{field_name} must be at most {max_value}",
23
+ ) -> StaticaConfig:
24
+ return cls(
25
+ type_error_message=type_error_message,
26
+ min_length_error_message=min_length_error_message,
27
+ max_length_error_message=max_length_error_message,
28
+ min_value_error_message=min_value_error_message,
29
+ max_value_error_message=max_value_error_message,
30
+ )
31
+
32
+
33
+ default_config = StaticaConfig.create()